php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #75590 Fatal error when removing optional argument in subclass (BC break).
Submitted: 2017-11-29 17:02 UTC Modified: 2019-03-16 09:20 UTC
Votes:1
Avg. Score:3.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:0 (0.0%)
From: christoph at burschka dot de Assigned:
Status: Not a bug Package: *General Issues
PHP Version: 7.2.0RC6 OS: MacOS
Private report: No CVE-ID: None
 [2017-11-29 17:02 UTC] christoph at burschka dot de
Description:
------------
In this inheritance chain, an interface defines a function without an argument, then an implementing class adds an optional argument, and a subclass defines the function with the original signature from the interface (no argument).

This works in PHP 7.1.11, but triggers E_ERROR in PHP 7.2.0RC6.

(Note: Without the interface, simply removing an optional argument in a subclass is E_WARNING on both 7.1.11 and 7.2.0RC6.)

Test script:
---------------
interface A {
  public function f();
}

class B implements A {
  public function f(A $x = NULL) {}
}

class C extends B {
  public function f() {}
}

Expected result:
----------------
Same behavior in PHP 7.2.0RC6 as PHP 7.1.11, or at worst a non-fatal warning/deprecation.

Actual result:
--------------
No warning in 7.1.11, E_ERROR in 7.2.0RC6.

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2017-11-29 17:08 UTC] christoph at burschka dot de
Also note: If the interface declares the optional argument as well, then the result is a fatal error in both 7.1.11 and 7.2.0RC6.
 [2017-12-08 22:34 UTC] pollita@php.net
-Status: Open +Status: Not a bug
 [2017-12-08 22:34 UTC] pollita@php.net
The fact that PHP < 7.2 accepted this was an unintentional side-effect.  The code you present doesn't follow valid inheritance contract.


Consider:
function foo(B $b) {
 $b->f(new A);
}

That code *should* always work, because B::f() declares a contract by which it accepts an instance of A as an argument, and therefore all children of B must adhere to that contract.  However, the following will fail, even in 7.1

foo(new C);

Because while C is a valid instance of B and will pass the type check, C::f() does not accept arguments and thus violates its parent's contract.
 [2019-03-16 05:48 UTC] sshambir at gmail dot com
Could you at least document this breaking change?
 [2019-03-16 09:20 UTC] nikic@php.net
@sshambir: Please open a new documentation bug report for that, it will be forgotten here.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sun Oct 06 23:01:26 2024 UTC