Strict Standards: Declaration of childClass::customMethod() should be compatible with that of parentClass::customMethod()
What are possible causes of this error in PHP? Where can I find information about what it means to be compatible?
childClass::customMethod() has different arguments, or a different access level (public/private/protected) than parentClass::customMethod().
This message means that there are certain possible method calls which may fail at run-time. Suppose you have
class A { public function foo($a = 1) {;}}
class B extends A { public function foo($a) {;}}
function bar(A $a) {$a->foo();}
The compiler only checks the call $a->foo() against the requirements of A::foo() which requires no parameters. $a may however be an object of class B which requires a parameter and so the call would fail at runtime.
This however can never fail and does not trigger the error
class A { public function foo($a) {;}}
class B extends A { public function foo($a = 1) {;}}
function bar(A $a) {$a->foo();}
So no method may have more required parameters than its parent method.
The same message is also generated when type hints do not match, but in this case PHP is even more restrictive. This gives an error:
class A { public function foo(StdClass $a) {;}}
class B extends A { public function foo($a) {;}}
as does this:
class A { public function foo($a) {;}}
class B extends A { public function foo(StdClass $a) {;}}
That seems more restrictive than it needs to be and I assume is due to internals.
Visibility differences cause a different error, but for the same basic reason. No method can be less visible than its parent method.
if you wanna keep OOP form without turning any error off, you can also:
class A
{
public function foo() {
;
}
}
class B extends A
{
/*instead of :
public function foo($a, $b, $c) {*/
public function foo() {
list($a, $b, $c) = func_get_args();
// ...
}
}
Just to expand on this error in the context of an interface, if you are type hinting your function parameters like so:
interface A
use Bar;
interface A
{
public function foo(Bar $b);
}
Class B
class B implements A
{
public function foo(Bar $b);
}
If you have forgotten to include the use statement on your implementing class (Class B), then you will also get this error even though the method parameters are identical.
I faced this problem while trying to extend an existing class from GitHub. I'm gonna try to explain myself, first writing the class as I though it should be, and then the class as it is now.
What I though
namespace mycompany\CutreApi;
use mycompany\CutreApi\ClassOfVendor;
class CutreApi extends \vendor\AwesomeApi\AwesomeApi
{
public function whatever(): ClassOfVendor
{
return new ClassOfVendor();
}
}
What I've finally done
namespace mycompany\CutreApi;
use \vendor\AwesomeApi\ClassOfVendor;
class CutreApi extends \vendor\AwesomeApi\AwesomeApi
{
public function whatever(): ClassOfVendor
{
return new \mycompany\CutreApi\ClassOfVendor();
}
}
So seems that this errror raises also when you're using a method that return a namespaced class, and you try to return the same class but with other namespace. Fortunately I have found this solution, but I do not fully understand the benefit of this feature in php 7.2, for me it is normal to rewrite existing class methods as you need them, including the redefinition of input parameters and / or even behavior of the method.
One downside of the previous aproach, is that IDE's could not recognise the new methods implemented in \mycompany\CutreApi\ClassOfVendor(). So, for now, I will go with this implementation.
Currently done
namespace mycompany\CutreApi;
use mycompany\CutreApi\ClassOfVendor;
class CutreApi extends \vendor\AwesomeApi\AwesomeApi
{
public function getWhatever(): ClassOfVendor
{
return new ClassOfVendor();
}
}
So, instead of trying to use "whatever" method, I wrote a new one called "getWhatever". In fact both of them are doing the same, just returning a class, but with diferents namespaces as I've described before.
Hope this can help someone.
This question already has answers here:
Override method parameter with child interface as a new parameter
(2 answers)
Abstract function parameter type hint overriding in PHP 7
(2 answers)
Closed 3 years ago.
This code of dependency inversion should work fine but instead it gives error.
What am I doing wrong in here?
interface A { }
abstract class B implements A { }
class C extends B { }
abstract class D {
public function foo(A $a) { }
}
class E extends D {
public function foo(C $c) { }
}
The error is:
Warning: Declaration of E::foo(C $c) should be compatible with D::foo(A $a) in [...][...] on line 24
Surprisingly, doing the same for the constructor method works just fine:
interface A { }
abstract class B implements A { }
class C extends B { }
abstract class D {
public function __construct(A $a) { }
public function foo(A $a) { }
}
class E extends D {
public function __construct(C $c) { }
public function foo(A $c) { }
}
There are two questions here.
Why the first part raises a WARNING: the error is pretty explicit. Any time you override a method you need to respect the parent's signature, so a client application's expectations are met.
class Foo {}
class Bar extends Foo {}
class A {
public function test(Foo $foo) {}
}
class B extends A {
public function test(Bar $bar) {}
}
Now, since B extends A, and A::test() expects a Foo, a user might try to do this:
$a = new A();
$b = new B();
$foo = new Foo();
$bar = new Bar();
$b->test($bar);
$b->test($foo);
The first call to test() would work, but the second would fail (and fatally): a Foo is not a Bar.
The parameter type is more restrictive than the original, and thus breaks expectations from client applications. Note that if we had a legal declaration (B::test(Foo)), we could still call $b->test($bar) and would work as expected, so changing the signature is not really necessary.
In November 2019, When PHP 7.4 is released, contravariance will be supported for parameter types, and covariance will be supported for return types; so your example would still be invalid.
Finally, notice that the error raised is a WARNING, it won't crash the program immediately. But it is warning you that you are opening your application to behaviour that might crash it, and that's it's generally poor design (for the reasons explained above).
The second question: Why you do not get the same warning for the constructor? They do not raise this warning by design. If you check the docs, you'll find this:
Unlike with other methods, PHP will not generate an E_STRICT level error message when __construct() is overridden with different parameters than the parent __construct() method has.
Why constructors are treated differently? Because it is generally understood that constructors are not part of the "public API" of an object, and do not need to be subjected to the same constraints. The Liskov Substitution Principle deals with objects, not with classes; and before an class is instantiated there is yet no object. Thus, the constructor is out of scope.
You can read more about this here, for example.
TL;DR C is implementing A, but it can also inherit other methods from B which implementing A doesn't guarantee. This creates situation where two classes of same inherited type can have two methods with different signatures. A sub-class must accept all inputs that the parent class would accept, but it can accept additional inputs if it wants,
Let's extend your example.
Nothing crazy, just some example methods.
interface A
{
public function gotA();
}
abstract class B implements A
{
abstract public function gotB();
}
class C extends B
{
public function gotA()
{
// ...
}
public function gotB()
{
// ...
}
}
I can agree that C is indirectly implementing A, but it also contains methods from B, so the call in E::foo() would be perfectly fine.
abstract class D
{
public function foo(A $a)
{
$a->gotA();
}
}
class E extends D
{
public function foo(C $c)
{
$c->gotB();
}
}
Another example class implementing A.
class ExampleA implements A
{
public function gotA()
{
// ...
}
}
Now the fun part. Assume this function anywhere else in your code. It assumes D (expecting A in foo) as parameter.
But E is also instanceof D and can be passed to x, but it expects C in foo which ExampleA has nothing to do with.
function x(D $d)
{
$exampleA = new ExampleA();
$d->foo($exampleA);
}
$e = new E();
x($e);
To sum up, the contract for function x has been met and yet the function broke.
You ended up with two 'different' D types. The one expecting A and the one expecting C.
As for why it doesn't throw warning with __constructor I don't know. Need further investigation.
I have a strange warning concerning PHP strict standards in my debug.log.
PHP Strict standards: Declaration of gb_EntryList::fields() should be compatible with mgr_LinearModelCollection::fields($mKey = NULL) in ... on line 339
So far so bad, but line 339 holds the definition of the gb_EntryList class
class gb_EntryList extends mgr_mySQLModel
and gb_EntryList does not define fields() at all. It inherits this from mgr_mySQLModel:
abstract class mgr_mySQLModel extends mgr_LinearModelCollection implements mgr_mySQLModelUpdateable {
...
function fields($mKey = null) { ... }
}
Originally, I forgot to put the = null into the declaration, which produced similar messages about mgr_mySQLModel. But these are gone now.
The code runs nicely, but what does this message want to tell me?
PHP version:
PHP 5.4.4-14+deb7u5 (cli) (built: Oct 3 2013 09:24:58)
Update:
I dug a little deeper into the issue. Interestingly the following code should have the same structure, but is fine with php -d error_reporting=4095 -l:
abstract class A {
function foo($sText = ""){
echo "A.foo($sText)\n";
}
abstract function bar();
}
abstract class B extends A {
function foo($sText = ""){
echo "B.foo($sText)\n";
}
}
class C extends B {
function bar(){
echo "C.bar()\n";
}
}
$c = new C();
$c->foo('in C');
The actual classes are too big to reproduce them here. But the structure is apart from interface inheritence the same. However, the above code appears to be fine. The actual situation is slightly more complex:
abstract class mgr_LinearModelCollection implements IteratorAggregate, Countable, ArrayAccess {
protected $sItemClass;
function getIterator() { }
function count(){ }
function offsetExists($offset){ }
function offsetGet($offset){ }
function offsetUnset($offset){ }
function offsetSet($offset, $value){ }
function fields($mKey = null){
$aDummy = call_user_func(array($this->sItemClass,'dummyArray'),$mKey);
return array_keys($aDummy);
}
}
interface mgr_mySQLModelUpdateable {
static function updateTable(array $aOpts = array());
}
abstract class mgr_mySQLModel extends mgr_LinearModelCollection implements mgr_mySQLModelUpdateable{
protected $aFieldNames = null;
function fields($mKey = null){
if(!is_array($this->aFieldNames)) return false;
return $this->aFieldNames;
}
}
class gb_EntryList extends mgr_mySQLModel {
static function updateTable(array $aOpts = array()){ }
}
There are of course many more functions and the { } are filled with code, but apart from that this is the real unchanged code, which produces the said error message. I currently lack any idea, why the toy model is fine, but the real one is not. Any hints?
This E_STRICT message warns about a violation of the Liskov substitution principle. It means that a method that was already defined in the superclass needs to be callable with the arguments of the method in the superclass.
This will trigger the message:
class Super {
public function foo($argument) {
echo $argument;
}
}
class Child extends Super {
public function foo() {
parent::foo('bar');
}
}
Output:
Strict Standards: Declaration of Child::foo() should be compatible
with Super::foo($argument) in ... on line 15
The fact that you say that field() is not declared in gb_EntryList is the clue to what's wrong. mgr_mySQLModel is an ABSTRACT class, if you look in the PHP manual entry for abstract classes the clue is in the line that says "When inheriting from an abstract class, all methods marked abstract in the parent's class declaration must be defined by the child". So although PHP is magically working out that you want the parent field() method, you really should also be declaring it in the child class too.
I'm looking for a way to transparently run code when a class is defined - more importantly, when the class is extended.
For example, if I have:
class A
{ function define()
{ echo "A has been defined!\n";
}
__magicDefine
{ define();
}
}
class B extends A
{
}
I'd like that to print "A has been defined!\n". Is this impossible?
That would be impossible, yeah. Nothing gets called on class definition.
This concept is even sort of aggressively unsupported; try writing
class foo {
static function __construct() {
echo "hi!";
}
}
and you'll get Fatal error: Constructor blah::__construct() cannot be static.
I guess what you're trying to do is keep track of objects that are running? Not exactly sure what your end goal is here.
Perhaps you're looking for the ReflectionClass at run time? You can determine if a class exists and what the extended class is.
It also sounds like what you're aiming for is an object factory that keeps track of objects that are being used. Look up singletons, factory, and static member functions/variables concepts for those.
As for this:
class A
{
public function __construct()
{ print "A has been called";
}
}
if class B overrides the constructor, it's not going to call A's constructor. Ex:
class B extends A
{
public function __construct()
{ print "B has been called";
// parent::__construct(); /// would print out A has been called
}
}
However in code, you can check if B is an instance of A one of many ways:
function doSomethingWithA(A $a)....
function doSmoethingWithA($a)
{
if($a instanceof A)
{
// blah
}
}
Don't know if that helps much.
In Java, this is possible, by using a "java agent" which would register a java.lang.instrument.ClassFileTransformer with the JVM.
If I have several classes with functions that I need but want to store separately for organisation, can I extend a class to have both?
i.e. class a extends b extends c
edit: I know how to extend classes one at a time, but I'm looking for a method to instantly extend a class using multiple base classes - AFAIK you can't do this in PHP but there should be ways around it without resorting to class c extends b, class b extends a
If you really want to fake multiple inheritance in PHP 5.3, you can use the magic function __call().
This is ugly though it works from class A user's point of view :
class B {
public function method_from_b($s) {
echo $s;
}
}
class C {
public function method_from_c($s) {
echo $s;
}
}
class A extends B
{
private $c;
public function __construct()
{
$this->c = new C;
}
// fake "extends C" using magic function
public function __call($method, $args)
{
$this->c->$method($args[0]);
}
}
$a = new A;
$a->method_from_b("abc");
$a->method_from_c("def");
Prints "abcdef"
You cannot have a class that extends two base classes. You could not have the following:
// this is NOT allowed (for all you google speeders)
Matron extends Nurse, HumanEntity
You could however have a hierarchy as follows...
Matron extends Nurse
Consultant extends Doctor
Nurse extends HumanEntity
Doctor extends HumanEntity
HumanEntity extends DatabaseTable
DatabaseTable extends AbstractTable
and so on.
You could use traits, which, hopefully, will be available from PHP 5.4.
Traits is a mechanism for code reuse in single inheritance languages such as PHP. A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies. The semantics of the combination of Traits and classes is defined in a way, which reduces complexity and avoids the typical problems associated with multiple inheritance and Mixins.
They are recognized for their potential in supporting better composition and reuse, hence their integration in newer versions of languages such as Perl 6, Squeak, Scala, Slate and Fortress. Traits have also been ported to Java and C#.
More information: https://wiki.php.net/rfc/traits
Classes are not meant to be just collections of methods. A class is supposed to represent an abstract concept, with both state (fields) and behaviour (methods) which changes the state. Using inheritance just to get some desired behaviour sounds like bad OO design, and exactly the reason why many languages disallow multiple inheritance: in order to prevent "spaghetti inheritance", i.e. extending 3 classes because each has a method you need, and ending up with a class that inherits 100 method and 20 fields, yet only ever uses 5 of them.
There are plans for adding mix-ins soon, I believe.
But until then, go with the accepted answer. You can abstract that out a bit to make an "extendable" class:
class Extendable{
private $extender=array();
public function addExtender(Extender $obj){
$this->extenders[] = $obj;
$obj->setExtendee($this);
}
public function __call($name, $params){
foreach($this->extenders as $extender){
//do reflection to see if extender has this method with this argument count
if (method_exists($extender, $name)){
return call_user_func_array(array($extender, $name), $params);
}
}
}
}
$foo = new Extendable();
$foo->addExtender(new OtherClass());
$foo->other_class_method();
Note that in this model "OtherClass" gets to 'know' about $foo. OtherClass needs to have a public function called "setExtendee" to set up this relationship. Then, if it's methods are invoked from $foo, it can access $foo internally. It will not, however, get access to any private/protected methods/variables like a real extended class would.
Use traits as base classes. Then use them in a parent class. Extend it .
trait business{
function sell(){
}
function buy(){
}
function collectMoney(){
}
}
trait human{
function think(){
}
function speak(){
}
}
class BusinessPerson{
use business;
use human;
// If you have more traits bring more
}
class BusinessWoman extends BusinessPerson{
function getPregnant(){
}
}
$bw = new BusinessWoman();
$bw ->speak();
$bw->getPregnant();
See now business woman logically inherited business and human both;
EDIT: 2020 PHP 5.4+ and 7+
As of PHP 5.4.0 there are "Traits" - you can use more traits in one class, so the final deciding point would be whether you want really an inheritance or you just need some "feature"(trait). Trait is, vaguely said, an already implemented interface that is meant to be just used.
Currently accepted answer by #Franck will work but it is not in fact multiple inheritance but a child instance of class defined out of scope, also there is the `__call()` shorthand - consider using just `$this->childInstance->method(args)` anywhere you need ExternalClass class method in "extended" class.
Exact answer
No you can't, respectively, not really, as manual of extends keyword says:
An extended class is always dependent on a single base class, that is,
multiple inheritance is not supported.
Real answer
However as #adam suggested correctly this does NOT forbids you to use multiple hierarchal inheritance.
You CAN extend one class, with another and another with another and so on...
So pretty simple example on this would be:
class firstInheritance{}
class secondInheritance extends firstInheritance{}
class someFinalClass extends secondInheritance{}
//...and so on...
Important note
As you might have noticed, you can only do multiple(2+) intehritance by hierarchy if you have control over all classes included in the process - that means, you can't apply this solution e.g. with built-in classes or with classes you simply can't edit - if you want to do that, you are left with the #Franck solution - child instances.
...And finally example with some output:
class A{
function a_hi(){
echo "I am a of A".PHP_EOL."<br>".PHP_EOL;
}
}
class B extends A{
function b_hi(){
echo "I am b of B".PHP_EOL."<br>".PHP_EOL;
}
}
class C extends B{
function c_hi(){
echo "I am c of C".PHP_EOL."<br>".PHP_EOL;
}
}
$myTestInstance = new C();
$myTestInstance->a_hi();
$myTestInstance->b_hi();
$myTestInstance->c_hi();
Which outputs
I am a of A
I am b of B
I am c of C
<?php
// what if we want to extend more than one class?
abstract class ExtensionBridge
{
// array containing all the extended classes
private $_exts = array();
public $_this;
function __construct() {$_this = $this;}
public function addExt($object)
{
$this->_exts[]=$object;
}
public function __get($varname)
{
foreach($this->_exts as $ext)
{
if(property_exists($ext,$varname))
return $ext->$varname;
}
}
public function __call($method,$args)
{
foreach($this->_exts as $ext)
{
if(method_exists($ext,$method))
return call_user_method_array($method,$ext,$args);
}
throw new Exception("This Method {$method} doesn't exists");
}
}
class Ext1
{
private $name="";
private $id="";
public function setID($id){$this->id = $id;}
public function setName($name){$this->name = $name;}
public function getID(){return $this->id;}
public function getName(){return $this->name;}
}
class Ext2
{
private $address="";
private $country="";
public function setAddress($address){$this->address = $address;}
public function setCountry($country){$this->country = $country;}
public function getAddress(){return $this->address;}
public function getCountry(){return $this->country;}
}
class Extender extends ExtensionBridge
{
function __construct()
{
parent::addExt(new Ext1());
parent::addExt(new Ext2());
}
public function __toString()
{
return $this->getName().', from: '.$this->getCountry();
}
}
$o = new Extender();
$o->setName("Mahdi");
$o->setCountry("Al-Ahwaz");
echo $o;
?>
I have read several articles discouraging inheritance in projects (as opposed to libraries/frameworks), and encouraging to program agaisnt interfaces, no against implementations.
They also advocate OO by composition: if you need the functions in class a and b, make c having members/fields of this type:
class C
{
private $a, $b;
public function __construct($x, $y)
{
$this->a = new A(42, $x);
$this->b = new B($y);
}
protected function DoSomething()
{
$this->a->Act();
$this->b->Do();
}
}
Multiple inheritance seems to work at the interface level.
I made a test on php 5.6.1.
Here is a working code:
<?php
interface Animal
{
public function sayHello();
}
interface HairyThing
{
public function plush();
}
interface Dog extends Animal, HairyThing
{
public function bark();
}
class Puppy implements Dog
{
public function bark()
{
echo "ouaf";
}
public function sayHello()
{
echo "hello";
}
public function plush()
{
echo "plush";
}
}
echo PHP_VERSION; // 5.6.1
$o = new Puppy();
$o->bark();
$o->plush();
$o->sayHello(); // displays: 5.6.16ouafplushhello
I didn't think that was possible, but I stumbled upon in the SwiftMailer source code, in the Swift_Transport_IoBuffer class, which has the following definition:
interface Swift_Transport_IoBuffer extends Swift_InputByteStream, Swift_OutputByteStream
I didn't play with it yet, but I thought it might be interesting to share.
I just solved my "multiple inheritance" problem with:
class Session {
public $username;
}
class MyServiceResponsetype {
protected $only_avaliable_in_response;
}
class SessionResponse extends MyServiceResponsetype {
/** has shared $only_avaliable_in_response */
public $session;
public function __construct(Session $session) {
$this->session = $session;
}
}
This way I have the power to manipulate session inside a SessionResponse which extends MyServiceResponsetype still being able to handle Session by itself.
If you want to check if a function is public see this topic : https://stackoverflow.com/a/4160928/2226755
And use call_user_func_array(...) method for many or not arguments.
Like this :
class B {
public function method_from_b($s) {
echo $s;
}
}
class C {
public function method_from_c($l, $l1, $l2) {
echo $l.$l1.$l2;
}
}
class A extends B {
private $c;
public function __construct() {
$this->c = new C;
}
public function __call($method, $args) {
if (method_exists($this->c, $method)) {
$reflection = new ReflectionMethod($this->c, $method);
if (!$reflection->isPublic()) {
throw new RuntimeException("Call to not public method ".get_class($this)."::$method()");
}
return call_user_func_array(array($this->c, $method), $args);
} else {
throw new RuntimeException("Call to undefined method ".get_class($this)."::$method()");
}
}
}
$a = new A;
$a->method_from_b("abc");
$a->method_from_c("d", "e", "f");
You are able to do that using Traits in PHP which announced as of PHP 5.4
Here is a quick tutorial for you, http://culttt.com/2014/06/25/php-traits/
One of the problems of PHP as a programming language is the fact that you can only have single inheritance. This means a class can only inherit from one other class.
However, a lot of the time it would be beneficial to inherit from multiple classes. For example, it might be desirable to inherit methods from a couple of different classes in order to prevent code duplication.
This problem can lead to class that has a long family history of inheritance which often does not make sense.
In PHP 5.4 a new feature of the language was added known as Traits. A Trait is kind of like a Mixin in that it allows you to mix Trait classes into an existing class. This means you can reduce code duplication and get the benefits whilst avoiding the problems of multiple inheritance.
Traits
PHP does not yet support multiple class inheritance, it does however support multiple interface inheritance.
See http://www.hudzilla.org/php/6_17_0.php for some examples.
PHP does not allow multiple inheritance, but you can do with implementing multiple interfaces. If the implementation is "heavy", provide skeletal implementation for each interface in a seperate class. Then, you can delegate all interface class to these skeletal implementations via object containment.
Always good idea is to make parent class, with functions ... i.e. add this all functionality to parent.
And "move" all classes that use this hierarchically down. I need - rewrite functions, which are specific.
class A extends B {}
class B extends C {}
Then A has extended both B and C