php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #71620 strange behavour of parser and exception's handler
Submitted: 2016-02-17 21:11 UTC Modified: 2019-01-25 16:36 UTC
From: miracle at rpz dot name Assigned:
Status: Not a bug Package: Scripting Engine problem
PHP Version: 7.0.3 OS: Linux
Private report: No CVE-ID: None
 [2016-02-17 21:11 UTC] miracle at rpz dot name
Description:
------------
Legacy code use PEAR's classes with php4-style constructor. Usualy In same file defined several global constants used in class. When this file included, then engine throw warning about deprecated constructor. After catch this "exception" we have new class (hooray!) and undefined constants from same file...

Test script:
---------------
foo.php:

<?php

define('LOST_CONSTANT', 42);

class Foo {
   public function foo() {
      // throw notice about deprecated constructor
   }
}
?>

main.php:

<?php

set_error_handler(function($errno, $errstr) {
    throw new Exception($errstr, $errno); // convert error to exception
});

try {
    include 'foo.php';
} catch (Exception $e) {
    printf("error %d with message: %s\n", $e->getCode(), $e->getMessage());
}

var_dump(
    class_exists('foo'), // exists!
    defined('LOST_CONSTANT') // where is my constant
);






Expected result:
----------------
error 8192 with message: Methods with the same name as their class will not be constructors in a future version of PHP; Foo has a deprecated constructor
main.php:14:
bool(true)
main.php:14:
bool(true)

Actual result:
--------------
error 8192 with message: Methods with the same name as their class will not be constructors in a future version of PHP; Foo has a deprecated constructor
main.php:14:
bool(true)
main.php:14:
bool(false)

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-02-17 21:47 UTC] requinix@php.net
https://3v4l.org/K4KhS

The deprecated constructor problem is being detected at compile time - before any code has been executed. You can test this by return;ing at the very beginning of the file. https://3v4l.org/tL7G2
By throwing the exception, the file is not executed at all and thus the constant will not be define()d.

The same problem exists if you use a variable: https://3v4l.org/oQlFm

With that said, given that the class exists, I would expect const to work too. (Or neither.) But it does not: https://3v4l.org/h02r8

Additionally, wrapping the class definition in an if(true) causes both the class and constant to be undefined, which is what I would have expected from the original code: https://3v4l.org/QdWiC
 [2016-07-14 10:22 UTC] dmitry@php.net
define() is a function that should be evaluated at run-time, but the included foo.php is not executed, because of exception, triggered by user error handler at compile-time.
 [2019-01-25 16:36 UTC] nikic@php.net
-Status: Open +Status: Not a bug
 [2019-01-25 16:36 UTC] nikic@php.net
I think the simplest way to think about this is that PHP hoists simple class declarations to the top of the file -- that's why you can make use of a class even if it is only defined further down in the same file. Of course, this also means that the exception thrown during class declaration is also hoisted to the top.

Conditional class declarations are excluded from this hoisting, and constant declarations are not hoisted either, leading to the results observed by @requinix.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Mar 28 10:01:26 2024 UTC