Always generate fatal error for LSP failures

RFC: https://wiki.php.net/rfc/lsp_errors
This commit is contained in:
Nikita Popov 2019-03-27 16:58:30 +01:00
parent 49c4ab3c39
commit fd2db11929
42 changed files with 143 additions and 186 deletions

View file

@ -66,6 +66,10 @@ PHP 8.0 UPGRADE NOTES
Additionally, care should be taken that error messages are not displayed in Additionally, care should be taken that error messages are not displayed in
production environments, which can result in information leaks. Please production environments, which can result in information leaks. Please
ensure that display_errors=Off is used in conjunction with error logging. ensure that display_errors=Off is used in conjunction with error logging.
. Inheritance errors due to incompatible method signatures (LSP violations)
will now always generate a fatal error. Previously a warning was generated
in some cases.
RFC: https://wiki.php.net/rfc/lsp_errors
- COM: - COM:
. Removed the ability to import case-insensitive constants from type . Removed the ability to import case-insensitive constants from type

View file

@ -13,4 +13,4 @@ class Sub extends Base {
} }
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of & Sub::test() should be compatible with & Base::test($foo, array $bar, $option = NULL, $extra = 'llllllllll...') in %sargument_restriction_001.php on line %d Fatal error: Declaration of & Sub::test() must be compatible with & Base::test($foo, array $bar, $option = NULL, $extra = 'llllllllll...') in %sargument_restriction_001.php on line %d

View file

@ -13,4 +13,4 @@ class Sub extends Base {
} }
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of Sub::test($foo, array &$bar) should be compatible with Base::test($foo, array &$bar, $option = NULL, $extra = 3.1415926535898) in %sargument_restriction_002.php on line %d Fatal error: Declaration of Sub::test($foo, array &$bar) must be compatible with Base::test($foo, array &$bar, $option = NULL, $extra = 3.1415926535898) in %sargument_restriction_002.php on line %d

View file

@ -16,4 +16,4 @@ class Sub extends Base {
} }
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of Sub::test() should be compatible with Base::test(Foo $foo, array $bar, $option = NULL, $extra = 'llllllllll...') in %sargument_restriction_003.php on line %d Fatal error: Declaration of Sub::test() must be compatible with Base::test(Foo $foo, array $bar, $option = NULL, $extra = 'llllllllll...') in %sargument_restriction_003.php on line %d

View file

@ -13,4 +13,4 @@ class Sub extends Base {
} }
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of Sub::test($foo, $extra) should be compatible with Base::test($foo, $extra = Array) in %sargument_restriction_006.php on line %d Fatal error: Declaration of Sub::test($foo, $extra) must be compatible with Base::test($foo, $extra = Array) in %sargument_restriction_006.php on line %d

View file

@ -1,17 +0,0 @@
--TEST--
Bug #47981 (error handler not called regardless)
--INI--
error_reporting=0
--FILE--
<?php
function errh($errno, $errstr) {
var_dump($errstr);
}
set_error_handler("errh");
interface a{}
class b implements a { function f($a=1) {}}
class c extends b {function f() {}}
?>
--EXPECT--
string(60) "Declaration of c::f() should be compatible with b::f($a = 1)"

View file

@ -53,32 +53,6 @@ public function setSelf(self $s) { }
} }
class Foo5 extends Base { ?>
public function setSelf(parent $s) { }
}
class Bar5 extends Foo5 {
public function setSelf(parent $s) { }
}
abstract class Foo6 extends Base {
abstract public function setSelf(parent $s);
}
class Bar6 extends Foo6 {
public function setSelf(Foo6 $s) { }
}
--EXPECTF-- --EXPECTF--
Warning: Declaration of Bar4::setSelf(Bar4 $s) should be compatible with Foo4::setSelf(Foo4 $s) in %sbug60573.php on line %d Fatal error: Declaration of Bar4::setSelf(Bar4 $s) must be compatible with Foo4::setSelf(Foo4 $s) in %s on line %d
Warning: Declaration of Bar5::setSelf(Foo5 $s) should be compatible with Foo5::setSelf(Base $s) in %sbug60573.php on line %d
Fatal error: Declaration of Bar6::setSelf(Foo6 $s) must be compatible with Foo6::setSelf(Base $s) in %sbug60573.php on line %d

View file

@ -0,0 +1,64 @@
--TEST--
Bug #60573 (type hinting with "self" keyword causes weird errors) -- variation 2
--FILE--
<?php
class Foo1 {
public function setSelf(self $s) { }
}
class Bar1 extends Foo1 {
public function setSelf(parent $s) { }
}
class Foo2 {
public function setSelf(Foo2 $s) { }
}
class Bar2 extends Foo2 {
public function setSelf(parent $s) { }
}
class Base {
}
class Foo3 extends Base{
public function setSelf(parent $s) { }
}
class Bar3 extends Foo3 {
public function setSelf(Base $s) { }
}
class Foo4 {
public function setSelf(self $s) { }
}
class Foo5 extends Base {
public function setSelf(parent $s) { }
}
class Bar5 extends Foo5 {
public function setSelf(parent $s) { }
}
?>
--EXPECTF--
Fatal error: Declaration of Bar5::setSelf(Foo5 $s) must be compatible with Foo5::setSelf(Base $s) in %sbug60573_2.php on line %d

View file

@ -1,22 +0,0 @@
--TEST--
Bug #63336 (invalid E_NOTICE error occur)
--FILE--
<?php
error_reporting(E_ALL & ~E_WARNING);
define("TEST", "123");
class Base {
const DUMMY = "XXX";
public function foo($var=TEST, $more=null) { return true; }
public function bar($more=self::DUMMY) { return true; }
}
class Child extends Base {
const DUMMY = "DDD";
public function foo($var=TEST, array $more = array()) { return true; }
public function bar($var, $more=self::DUMMY) { return true; }
}
?>
--EXPECTF--
Warning: Declaration of Child::foo($var = TEST, array $more = Array) should be compatible with Base::foo($var = TEST, $more = NULL) in %sbug63336.php on line %d
Warning: Declaration of Child::bar($var, $more = self::DUMMY) should be compatible with Base::bar($more = self::DUMMY) in %sbug63336.php on line %d

View file

@ -26,5 +26,4 @@ $o = new Smooth1();
echo "okey"; echo "okey";
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of Smooth1::insert(array $data) should be compatible with Noisy1::insert(array $data, $option1 = NULL) in %sbug64988.php on line 17 Fatal error: Declaration of Smooth1::insert(array $data) must be compatible with Noisy1::insert(array $data, $option1 = NULL) in %sbug64988.php on line 17
okey

View file

@ -15,10 +15,10 @@ set_error_handler(function($_, $msg, $file) {
/* This is just a particular example of a non-fatal compile-time error /* This is just a particular example of a non-fatal compile-time error
* If this breaks in future, just find another example and use it instead */ * If this breaks in future, just find another example and use it instead */
eval('class A { function test() { } } class B extends A { function test($a) { } }'); eval('class A { private function __invoke() { } }');
?> ?>
--EXPECTF-- --EXPECTF--
string(62) "Declaration of B::test($a) should be compatible with A::test()" string(76) "The magic method __invoke() must have public visibility and cannot be static"
string(%d) "%s(%d) : eval()'d code" string(%d) "%s(%d) : eval()'d code"
string(1) "X" string(1) "X"

View file

@ -1,7 +1,9 @@
<?php <?php
class b extends a { class b extends a {
public function test() { private function __invoke() {}
public function test($arg = c::TESTCONSTANT) {
echo __METHOD__ . "()\n"; echo __METHOD__ . "()\n";
parent::test(); parent::test();
} }

View file

@ -2,6 +2,8 @@
bug67436: Autoloader isn't called if user defined error handler is present bug67436: Autoloader isn't called if user defined error handler is present
--INI-- --INI--
error_reporting=-1 error_reporting=-1
--SKIPIF--
<?php if (extension_loaded('Zend OPCache')) die('skip Opcache overrides error handler'); ?>
--FILE-- --FILE--
<?php <?php
@ -12,6 +14,7 @@ spl_autoload_register(function($classname) {
}); });
set_error_handler(function ($errno, $errstr, $errfile, $errline) { set_error_handler(function ($errno, $errstr, $errfile, $errline) {
var_dump($errstr);
}, error_reporting()); }, error_reporting());
a::staticTest(); a::staticTest();
@ -19,5 +22,6 @@ a::staticTest();
$b = new b(); $b = new b();
$b->test(); $b->test();
--EXPECT-- --EXPECT--
string(76) "The magic method __invoke() must have public visibility and cannot be static"
b::test() b::test()
a::test(c::TESTCONSTANT) a::test(c::TESTCONSTANT)

View file

@ -14,6 +14,6 @@ a::staticTest();
$b = new b(); $b = new b();
$b->test(); $b->test();
--EXPECTF-- --EXPECTF--
Warning: Declaration of b::test() should be compatible with a::test($arg = c::TESTCONSTANT) in %s%ebug67436%eb.inc on line %d Warning: The magic method __invoke() must have public visibility and cannot be static in %s on line %d
b::test() b::test()
a::test(c::TESTCONSTANT) a::test(c::TESTCONSTANT)

View file

@ -19,4 +19,4 @@ class B extends Foo
} }
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of T::bar() should be compatible with Foo::bar($a = 'Foo') in %sbug70957.php on line %d Fatal error: Declaration of T::bar() must be compatible with Foo::bar($a = 'Foo') in %sbug70957.php on line %d

View file

@ -9,4 +9,4 @@ class B extends A {
public function m(array $a = []) {} public function m(array $a = []) {}
} }
--EXPECTF-- --EXPECTF--
Warning: Declaration of B::m(array $a = Array) should be compatible with A::m(?array $a = NULL) in %sbug71428.1.php on line 6 Fatal error: Declaration of B::m(array $a = Array) must be compatible with A::m(?array $a = NULL) in %sbug71428.1.php on line 6

View file

@ -7,4 +7,4 @@ class B { public function m(A $a = NULL, $n) { echo "B.m";} };
class C extends B { public function m(A $a , $n) { echo "C.m";} }; class C extends B { public function m(A $a , $n) { echo "C.m";} };
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of C::m(A $a, $n) should be compatible with B::m(?A $a, $n) in %sbug71428.3.php on line 4 Fatal error: Declaration of C::m(A $a, $n) must be compatible with B::m(?A $a, $n) in %sbug71428.3.php on line 4

View file

@ -10,11 +10,11 @@ set_error_handler(function($_, $msg, $file) {
/* This is just a particular example of a non-fatal compile-time error /* This is just a particular example of a non-fatal compile-time error
* If this breaks in future, just find another example and use it instead */ * If this breaks in future, just find another example and use it instead */
eval('class A { function test() { } } class B extends A { function test($a) { } }'); eval('class A { private function __invoke() { } }');
?> ?>
--EXPECTF-- --EXPECTF--
string(62) "Declaration of B::test($a) should be compatible with A::test()" string(76) "The magic method __invoke() must have public visibility and cannot be static"
string(%d) "%s(%d) : eval()'d code" string(%d) "%s(%d) : eval()'d code"
Notice: Undefined variable: undefined in %s on line %d Notice: Undefined variable: undefined in %s on line %d

View file

@ -17,8 +17,6 @@ class test3 extends test {
function foo($arg) {} function foo($arg) {}
} }
echo "Done\n";
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of test3::foo($arg) should be compatible with test::foo() in %s on line %d Fatal error: Declaration of test3::foo($arg) must be compatible with test::foo() in %s on line %d
Done

View file

@ -17,8 +17,6 @@ class test3 extends test {
function foo($arg, $arg2) {} function foo($arg, $arg2) {}
} }
echo "Done\n";
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of test3::foo($arg, $arg2) should be compatible with test::foo($arg) in %s on line %d Fatal error: Declaration of test3::foo($arg, $arg2) must be compatible with test::foo($arg) in %s on line %d
Done

View file

@ -17,8 +17,6 @@ class test3 extends test {
function foo(&$arg) {} function foo(&$arg) {}
} }
echo "Done\n";
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of test3::foo(&$arg) should be compatible with test::foo($arg) in %s on line %d Fatal error: Declaration of test3::foo(&$arg) must be compatible with test::foo($arg) in %s on line %d
Done

View file

@ -17,8 +17,6 @@ class test3 extends test {
function foo() {} function foo() {}
} }
echo "Done\n";
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of test3::foo() should be compatible with & test::foo() in %s on line %d Fatal error: Declaration of test3::foo() must be compatible with & test::foo() in %s on line %d
Done

View file

@ -17,8 +17,6 @@ class test3 extends test {
function foo($arg, $arg2) {} function foo($arg, $arg2) {}
} }
echo "Done\n";
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of test3::foo($arg, $arg2) should be compatible with test::foo($arg, $arg2 = NULL) in %s on line %d Fatal error: Declaration of test3::foo($arg, $arg2) must be compatible with test::foo($arg, $arg2 = NULL) in %s on line %d
Done

View file

@ -17,8 +17,6 @@ class test3 extends test {
function foo($arg, &$arg2) {} function foo($arg, &$arg2) {}
} }
echo "Done\n";
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of test3::foo($arg, &$arg2) should be compatible with test::foo($arg, &$arg2 = NULL) in %s on line %d Fatal error: Declaration of test3::foo($arg, &$arg2) must be compatible with test::foo($arg, &$arg2 = NULL) in %s on line %d
Done

View file

@ -17,8 +17,6 @@ class test3 extends test {
function foo(Test3 $arg) {} function foo(Test3 $arg) {}
} }
echo "Done\n";
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of test3::foo(Test3 $arg) should be compatible with test::foo(Test $arg) in %s on line %d Fatal error: Declaration of test3::foo(Test3 $arg) must be compatible with test::foo(Test $arg) in %s on line %d
Done

View file

@ -2,12 +2,6 @@
Bug #71978 (Existence of return type hint affects other compatibility rules) Bug #71978 (Existence of return type hint affects other compatibility rules)
--FILE-- --FILE--
<?php <?php
class A {
function foo(int $a) {}
}
class B extends A {
function foo(string $a) {}
}
class A1 { class A1 {
function foo(int $a): int {} function foo(int $a): int {}
} }
@ -16,6 +10,4 @@ class B1 extends A1 {
} }
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of B::foo(string $a) should be compatible with A::foo(int $a) in %s on line %d Fatal error: Declaration of B1::foo(string $a): int must be compatible with A1::foo(int $a): int in %s on line %d
Warning: Declaration of B1::foo(string $a): int should be compatible with A1::foo(int $a): int in %s on line %d

View file

@ -21,4 +21,4 @@ class Bar extends Foo {
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of Bar::testScalar(iterable $iterable) should be compatible with Foo::testScalar(int $int) in %s on line %d Fatal error: Declaration of Bar::testScalar(iterable $iterable) must be compatible with Foo::testScalar(int $int) in %s on line %d

View file

@ -1,5 +1,5 @@
--TEST-- --TEST--
Parameter variance with no type Parameter variance with no type (class)
--FILE-- --FILE--
<?php <?php
@ -8,11 +8,6 @@ class Foo {
function testBothClass(Foo $foo) {} function testBothClass(Foo $foo) {}
function testChildClass($foo) {} function testChildClass($foo) {}
function testNoneClass($foo) {} function testNoneClass($foo) {}
function testParentBuiltin(int $foo) {}
function testBothBuiltin(int $foo) {}
function testChildBuiltin($foo) {}
function testNoneBuiltin($foo) {}
} }
class Bar extends Foo { class Bar extends Foo {
@ -20,15 +15,8 @@ class Bar extends Foo {
function testBothClass(Foo $foo) {} function testBothClass(Foo $foo) {}
function testChildClass(Foo $foo) {} function testChildClass(Foo $foo) {}
function testNoneClass($foo) {} function testNoneClass($foo) {}
function testParentBuiltin($foo) {}
function testBothBuiltin(int $foo) {}
function testChildBuiltin(int $foo) {}
function testNoneBuiltin($foo) {}
} }
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of Bar::testChildClass(Foo $foo) should be compatible with Foo::testChildClass($foo) in %s on line %d Fatal error: Declaration of Bar::testChildClass(Foo $foo) must be compatible with Foo::testChildClass($foo) in %s on line %d
Warning: Declaration of Bar::testChildBuiltin(int $foo) should be compatible with Foo::testChildBuiltin($foo) in %s on line %d

View file

@ -0,0 +1,22 @@
--TEST--
Parameter variance with no type (builtin)
--FILE--
<?php
class Foo {
function testParentBuiltin(int $foo) {}
function testBothBuiltin(int $foo) {}
function testChildBuiltin($foo) {}
function testNoneBuiltin($foo) {}
}
class Bar extends Foo {
function testParentBuiltin($foo) {}
function testBothBuiltin(int $foo) {}
function testChildBuiltin(int $foo) {}
function testNoneBuiltin($foo) {}
}
?>
--EXPECTF--
Fatal error: Declaration of Bar::testChildBuiltin(int $foo) must be compatible with Foo::testChildBuiltin($foo) in %s on line %d

View file

@ -633,29 +633,11 @@ static void do_inheritance_check_on_method(zend_function *child, zend_function *
} }
if (UNEXPECTED(!zend_do_perform_implementation_check(child, parent))) { if (UNEXPECTED(!zend_do_perform_implementation_check(child, parent))) {
int error_level;
const char *error_verb;
zend_string *method_prototype = zend_get_function_declaration(parent); zend_string *method_prototype = zend_get_function_declaration(parent);
zend_string *child_prototype = zend_get_function_declaration(child); zend_string *child_prototype = zend_get_function_declaration(child);
zend_error_at(E_COMPILE_ERROR, NULL, func_lineno(child),
if (child->common.prototype && ( "Declaration of %s must be compatible with %s",
child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT ZSTR_VAL(child_prototype), ZSTR_VAL(method_prototype));
)) {
error_level = E_COMPILE_ERROR;
error_verb = "must";
} else if ((parent->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) &&
(!(child->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
!zend_do_perform_type_hint_check(child, child->common.arg_info - 1, parent, parent->common.arg_info - 1) ||
(ZEND_TYPE_ALLOW_NULL(child->common.arg_info[-1].type) && !ZEND_TYPE_ALLOW_NULL(parent->common.arg_info[-1].type)))) {
error_level = E_COMPILE_ERROR;
error_verb = "must";
} else {
error_level = E_WARNING;
error_verb = "should";
}
zend_error_at(error_level, NULL, func_lineno(child),
"Declaration of %s %s be compatible with %s",
ZSTR_VAL(child_prototype), error_verb, ZSTR_VAL(method_prototype));
zend_string_efree(child_prototype); zend_string_efree(child_prototype);
zend_string_efree(method_prototype); zend_string_efree(method_prototype);
} }

View file

@ -9,4 +9,4 @@ class MyDateTime extends DateTime {
} }
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of MyDateTime::__set_state() should be compatible with DateTime::__set_state(array $array) in %s on line %d Fatal error: Declaration of MyDateTime::__set_state() must be compatible with DateTime::__set_state(array $array) in %s on line %d

View file

@ -10,10 +10,6 @@ MySQLPDOTest::skip();
<?php <?php
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc'); require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
// No silly strict mode warnings, please!
error_reporting(E_ALL^E_STRICT);
ini_set('display_errors', false);
try { try {
class MyPDO extends PDO { class MyPDO extends PDO {
@ -23,7 +19,7 @@ MySQLPDOTest::skip();
return call_user_func_array(array($this, 'parent::__construct'), func_get_args()); return call_user_func_array(array($this, 'parent::__construct'), func_get_args());
} }
public function exec() { public function exec($query) {
$this->protocol(); $this->protocol();
return call_user_func_array(array($this, 'parent::exec'), func_get_args()); return call_user_func_array(array($this, 'parent::exec'), func_get_args());
} }

View file

@ -14,4 +14,4 @@ class bar extends php_user_filter {
} }
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of bar::filter($in, $out, &$consumed) should be compatible with php_user_filter::filter($in, $out, &$consumed, $closing) in %s on line %d Fatal error: Declaration of bar::filter($in, $out, &$consumed) must be compatible with php_user_filter::filter($in, $out, &$consumed, $closing) in %s on line %d

View file

@ -9,4 +9,4 @@ class foo extends php_user_filter {
} }
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of foo::filter($in, $out, $consumed, $closing) should be compatible with php_user_filter::filter($in, $out, &$consumed, $closing) in %s on line %d Fatal error: Declaration of foo::filter($in, $out, $consumed, $closing) must be compatible with php_user_filter::filter($in, $out, &$consumed, $closing) in %s on line %d

View file

@ -9,4 +9,4 @@ class foo extends php_user_filter {
} }
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of foo::onCreate($var) should be compatible with php_user_filter::onCreate() in %s on line %d Fatal error: Declaration of foo::onCreate($var) must be compatible with php_user_filter::onCreate() in %s on line %d

View file

@ -14,7 +14,5 @@ class B extends A
} }
?> ?>
===DONE===
--EXPECTF-- --EXPECTF--
Warning: Declaration of B::f() should be compatible with A::f($x) in %sinheritance_003.php on line %d Fatal error: Declaration of B::f() must be compatible with A::f($x) in %sinheritance_003.php on line %d
===DONE===

View file

@ -5,7 +5,7 @@ ZE2 method inheritance without interfaces
class A class A
{ {
function f() {} function f() {}
} }
class B extends A class B extends A
@ -14,7 +14,5 @@ class B extends A
} }
?> ?>
===DONE===
--EXPECTF-- --EXPECTF--
Warning: Declaration of B::f($x) should be compatible with A::f() in %sinheritance_004.php on line %d Fatal error: Declaration of B::f($x) must be compatible with A::f() in %sinheritance_004.php on line %d
===DONE===

View file

@ -26,6 +26,4 @@ $b->foo(1);
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of C::foo() should be compatible with A::foo($arg1 = 1) in %s on line %d Fatal error: Declaration of C::foo() must be compatible with A::foo($arg1 = 1) in %s on line %d
int(1)
int(3)

View file

@ -18,5 +18,4 @@ $b->foo();
?> ?>
--EXPECTF-- --EXPECTF--
Warning: Declaration of B::foo() should be compatible with A::foo($arg = 1) in %s on line %d Fatal error: Declaration of B::foo() must be compatible with A::foo($arg = 1) in %s on line %d
foo

View file

@ -4,15 +4,11 @@ Check type hint compatibility in overrides with array hints.
<?php <?php
Class C { function f(array $a) {} } Class C { function f(array $a) {} }
echo "Compatible hint.\n"; // Compatible hint.
Class D1 extends C { function f(array $a) {} } Class D1 extends C { function f(array $a) {} }
echo "Class hint, should be array.\n"; // Class hint, should be array.
Class D2 extends C { function f(SomeClass $a) {} } Class D2 extends C { function f(SomeClass $a) {} }
?> ?>
==DONE==
--EXPECTF-- --EXPECTF--
Warning: Declaration of D2::f(SomeClass $a) should be compatible with C::f(array $a) in %s on line 8 Fatal error: Declaration of D2::f(SomeClass $a) must be compatible with C::f(array $a) in %s on line 8
Compatible hint.
Class hint, should be array.
==DONE==

View file

@ -4,11 +4,8 @@ Check type hint compatibility in overrides with array hints.
<?php <?php
Class C { function f(SomeClass $a) {} } Class C { function f(SomeClass $a) {} }
echo "Array hint, should be class.\n"; // Array hint, should be class.
Class D extends C { function f(array $a) {} } Class D extends C { function f(array $a) {} }
?> ?>
==DONE==
--EXPECTF-- --EXPECTF--
Warning: Declaration of D::f(array $a) should be compatible with C::f(SomeClass $a) in %s on line 5 Fatal error: Declaration of D::f(array $a) must be compatible with C::f(SomeClass $a) in %s on line 5
Array hint, should be class.
==DONE==

View file

@ -4,11 +4,8 @@ Check type hint compatibility in overrides with array hints.
<?php <?php
Class C { function f($a) {} } Class C { function f($a) {} }
echo "Array hint, should be nothing.\n"; // Array hint, should be nothing.
Class D extends C { function f(array $a) {} } Class D extends C { function f(array $a) {} }
?> ?>
==DONE==
--EXPECTF-- --EXPECTF--
Warning: Declaration of D::f(array $a) should be compatible with C::f($a) in %s on line 5 Fatal error: Declaration of D::f(array $a) must be compatible with C::f($a) in %s on line 5
Array hint, should be nothing.
==DONE==