php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #69116 Strict mode error triggered not consistently
Submitted: 2015-02-24 16:48 UTC Modified: 2020-03-05 17:48 UTC
From: m at klkvsk dot ru Assigned: nikic (profile)
Status: Closed Package: Class/Object related
PHP Version: 5.5.22 OS: Linux
Private report: No CVE-ID: None
 [2015-02-24 16:48 UTC] m at klkvsk dot ru
Description:
------------
PHP does not trigger strict error "Declaration .. should be compatible with .." when overriding method has incompatible arguments with base method. But when either parent or child class implements any interface, the error gets triggered. 
Example:
    error_reporting(-1);

    class A1 {
    	public function fn() {}
    }
    class B1 extends A1 {
    	public function fn($arg) {} // error is not triggered
    }

    interface I {}
    class A2 {
        public function fn() {}
    }
    class B2 extends A2 implements I {
        public function fn($arg) {} // error is triggered
    }


Another related bug that is probably a product of this bug, is when you have set error handler with function that throws an exception on E_STRICT, and then you put classes definition in try-catch, the child class would be defined without its interfaces. 
Example: 
    set_error_handler(
        function ($code, $string) { throw new Exception($string, $code); }, 
        E_STRICT
    );
    try {
        interface I1 {}
        interface I2 {}
        class A implements I1 { 
            public function fn() { echo 'foo'; } 
        }
        class B extends A implements I2 {
            public function fn($arg) { echo $arg; }
        }
    } catch (Exception $e) {
        // ignore
    }
    $b = new B();
    var_dump($b instanceof I1);         // outputs "bool(false)"
    var_dump($b instanceof I2);         // outputs "bool(false)"
    var_dump(class_implements('B'));    // outputs "array(1) { 'I1' => string(2) "I1" }"
    $b->fn('bar');                      // outputs "bar"

You can see that child class is defined and works, but it's interfaces are lost. Only parent classes interfaces are kept. The real-world usage of code like this might be implementation of an autoloader, where you would put class definitions in separate files and include them here inside try-catch. 

Test script:
---------------
<?php
error_reporting(-1);

class A1 {
	public function fn() {}
}
class B1 extends A1 {
	public function fn($arg) {}
}

interface I {}
class A2 {
	public function fn() {}
}
class B2 extends A2 implements I {
	public function fn($arg) {}
}


Expected result:
----------------
PHP Strict standards:  Declaration of B1::fn() should be compatible with A1::fn() in /tmp/test.php on line 7
PHP Stack trace:
PHP   1. {main}() /tmp/test.php:0
PHP Strict standards:  Declaration of B2::fn() should be compatible with A2::fn() in /tmp/test.php on line 15
PHP Stack trace:
PHP   1. {main}() /tmp/test.php:0


Actual result:
--------------
PHP Strict standards:  Declaration of B2::fn() should be compatible with A2::fn() in /tmp/test.php on line 15
PHP Stack trace:
PHP   1. {main}() /tmp/test.php:0

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-02-25 08:45 UTC] m at klkvsk dot ru
Correction: typo in second example, line 

    var_dump($b instanceof I1);

outputs "bool(true)".
 [2020-03-05 17:48 UTC] nikic@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: nikic
 [2020-03-05 17:48 UTC] nikic@php.net
First part: https://3v4l.org/Lpalj

Second part: https://3v4l.org/fkbOC

The first part has probably been fixed long ago, the second part is fixed in PHP 7.4. As such, all issues here seem to be resolved.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 19 00:01:29 2024 UTC