php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #41461 E_STRICT notice when overriding methods not defined by an Interface in hierarchy
Submitted: 2007-05-21 23:06 UTC Modified: 2010-05-21 11:57 UTC
Votes:9
Avg. Score:4.2 ± 1.2
Reproduced:8 of 9 (88.9%)
Same Version:7 (87.5%)
Same OS:6 (75.0%)
From: ralph at smashlabs dot com Assigned:
Status: Not a bug Package: Class/Object related
PHP Version: 5.*, 6CVS (2009-04-25) OS: *
Private report: No CVE-ID:
 [2007-05-21 23:06 UTC] ralph at smashlabs dot com
Description:
------------
When an interface is a parent of a class, the interface is implying a specific profile for a given function (here its __get) even though it is not defined in the interface itself.  This is making it impossible to overload and/or change the profile of the function in a descendant class.


Reproduce code:
---------------
The following will produce this notice:

Strict Standards: Declaration of Z_Concrete::__get() should be compatible with that of Z_Abstract::__get() in xxx on line 16

<?php

error_reporting(E_ALL | E_STRICT);

interface Z_Interface
{ }

abstract class Z_Abstract implements Z_Interface
{
  public function __get($name)
  {
    return;
  }
}

class Z_Concrete extends Z_Abstract
{
  public function & __get($name)
  {
    return null;
  }
}

$t = new Z_Concrete();





This code will not produce a notice:

<?php

error_reporting(E_ALL | E_STRICT);

abstract class Z_Abstract
{
  public function __get($name)
  {
    return;
  }
}

class Z_Concrete extends Z_Abstract
{
  public function & __get($name)
  {
    return null;
  }
}

$t = new Z_Concrete();

The only difference is that the former has an interface as a parent, the latter does not.


Expected result:
----------------
No E_STRICT notice raised

Actual result:
--------------
E_STRICT notice raised.

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2007-05-28 15:08 UTC] helly@php.net
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php

PHP follows strict is_a inheritance.

By the way, it is called signature and even if you could change it it would not solve the problem. And anyway it would break inheritance rules.
 [2007-05-28 17:42 UTC] ralph at smashlabs dot com
I am sorry, perhaps I should rephrase (I was rushed when I wrote the original bug report) and I don't think I was especially clear.

In general, we are speaking strictly of Method Overriding.  PHP currently allows concrete classes to override methods in abstract classes as demonstrated by this code:

webdeveloper@webdevelopment ~/tmp $ cat test_method_override.php 
<?php

error_reporting(E_ALL | E_STRICT);

class Z_Abstract
{
  public function someFunc($one, $two)
  {  }
}

class Z_Concrete extends Z_Abstract
{
  public function & someFunc($uno, $dos, $tres)
  {  }
}

$o = new Z_Concrete();
webdeveloper@webdevelopment ~/tmp $ php test_method_override.php 
webdeveloper@webdevelopment ~/tmp $ 

As you can see, no E_STRICT was triggered, thus allowing the concrete class to override the method from the abstract class.

On the other hand, when adding an _empty_ interface to the superclass hierarchy, the behavior changes.  The simple inclusion of an interface now (albeit empty) seemingly shouldn't add any complexities to method overriding for methods outside the scope of the interface itself.  I have done a bit more homework, and it seems like not alot of IS_A inheritance literature exists to describe this problem, let alone justify the behavior we are seeing in practice..  See code:

webdeveloper@webdevelopment ~/tmp $ cat test_method_override2.php 
<?php

error_reporting(E_ALL | E_STRICT);

interface Z_Interface
{ }

class Z_Abstract implements Z_Interface
{
  public function someFunc($one, $two)
  {  }
}

class Z_Concrete extends Z_Abstract
{
  public function & someFunc($uno, $dos, $tres)
  {  }
}

$o = new Z_Concrete();
webdeveloper@webdevelopment ~/tmp $ php test_method_override2.php 

Strict standards: Declaration of Z_Concrete::someFunc() should be compatible with that of Z_Abstract::someFunc() in /home/webdeveloper/tmp/test_method_override2.php on line 14



At the very least, I looks like one of the two is broken (At least in the spirit of OOP as it relates to polymorphism and overriding methods.)
 [2007-05-28 17:53 UTC] ralph at smashlabs dot com
PS. I did check this with the internals list before I posted.. And I think you actually confirmed it for me on the list

http://news.php.net/php.internals/29646

Thank you for your time,
-ralph
 [2007-06-19 21:52 UTC] ralph at smashlabs dot com
Marcus,

After re-reading, I didn't think that I was clear in my original bug report, so I attempted to clarify the matter (2 posts up).  I still think this is a problem and that it hinders the usage of interfaces as it restricts concrete classes from overriding methods introduced at the abstract layer, not the interface layer.

If this is still by design, go ahead and close, but I wanted to make absolutely sure as most people either do not care about E_STRICT, or haven't run into the problem yet ;)

Thanks again,
Ralph
 [2008-08-08 19:57 UTC] stas@php.net
I took a look into it, here's some findings:

1. There's no difference between how arguments are matched with and without interface. The difference is that with no interface binding would happen in this case in compile time, so if your error reporting did not have E_STRICT by default, error_reporting(E_ALL | E_STRICT) is not executed and so the error is not seen.

2. someFunc($uno, $dos, $tres) is not a good replacement for someFunc($uno, $dos) even ignoring the by-ref return, since it has extra required argument. Making it not required should pass the strict check.

3. I think it can be allowed to override function that returns by-val with function that returns by-ref, but not vice versa. 


 [2009-07-27 08:02 UTC] php at whoah dot net
Should this not be possible without errors or notices? I am 
overloading an overridden method. If memory serves me, I am able to do 
this in other OO languages (Java, .NET/C#).

class BaseClass {

	public function TestFunction ($parameter) {
		var_dump($parameter);
	}
}

class FooClass extends BaseClass {

	public function TestFunction () {
		parent::TestFunction('This is Foo');
	}
}

class BarClass extends BaseClass {

	public function TestFunction () {
		parent::TestFunction('This is Bar');
	}
}

$test = new FooClass();
$test->TestFunction();

$test = new BarClass();
$test->TestFunction();


Instead:

Strict Standards: Declaration of FooClass::TestFunction() should be 
compatible with that of BaseClass::TestFunction()

Strict Standards: Declaration of BarClass::TestFunction() should be 
compatible with that of BaseClass::TestFunction()
 [2009-11-03 18:17 UTC] markskilbeck at gmail dot com
PHP does not allow for method overloading.
 [2010-05-21 11:57 UTC] mike@php.net
-Status: Verified +Status: Bogus
 [2010-05-21 11:57 UTC] mike@php.net
as stas said, E_STRICT needs to be set prior parsing the file
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Sun Apr 20 03:02:42 2014 UTC