Why does this violate the Strict Standards?

5

Consider the following class definitions:

class SuperDate {}
class SubDate extends SuperDate {}

class Foo
{
    public function setDate(SubDate $date) {}
}

class Bar extends Foo
{
    public function setDate(SuperDate $date){}
}

$foo = new Foo();
$bar = new Bar();
$bar->setDate(new SubDate());
$foo->setDate(new SubDate());

This code gives the following error:

Strict standards: Declaration of Bar::setDate() should be compatible with Foo::setDate(SubDate $date)

Obviously, the reason is that the signature of Bar::setDate is different from that of Foo:setDate . In StackOverflow in English there is a similar question that refers a violation of the Principle of Substitution of Liskov as the cause of the "strict warning ", but the situation is slightly different because the subclass is more restrictive than the parent class.

However, in my case, the signature in Bar is more "wide" than in Foo and therefore completely interchangeable. That is, since Bar is a subtype of Foo, then objects of type Foo can be replaced by objects of type Bar without having to change the properties of the program.

So, my question is: Why does this code violate "Strict Standards"?

    
asked by anonymous 19.02.2014 / 20:42

3 answers

2

The method parameter of the child class must be of exactly the same type as the method parameter of the parent class.

  

In object-oriented programming, SOLID is an acronym for Single responsibility, Open-closed, Liskov substitution, Interface segregation and Dependency inversion.

     

The Liskov substitution principle says that in a computer program, if Bar is a subtype of Foo , then objects of type Foo can be changed by objects of type Bar without changing the properties of the program (correction, execution of the task, etc.).

     

In programs with strong typing, when you override a Foo method, if you change the signature of Bar , you are actually doing an overload >, since the original method and the new method have different signatures. However, since PHP has poor typing, this is not possible, since the compiler does not know which methods you are actually calling (so the reason you can not have two methods with the same name, even if their signatures are different.)

     

So, to avoid violating the principle of replacing Liskov, a strict standard warning warning is made, warning the programmer that there is a potential problem due to the change in the signature of the method of the child class .

(translated from: link

That is, instead of using:

class Foo
{
    public function setDate(SubDate $date) {}
}
class Bar extends Foo
{
    public function setDate(SuperDate $date) {}
}

Use:

class Foo
{
    public function setDate(SubDate $date) {}
}
class Bar extends Foo
{
    public function setDate(SubDate $date) {}
}
    
19.02.2014 / 21:36
2

I think the answer to this question is very simple.

This code violates the standard because standard is strict, and in its strict definition Compatibility , the signature of the methods must be identical .

This is the standard. So that's why this code violates the standard : standard determines that the signatures are identical . And that's the end point.

It has nothing to do with the signature of the method being more restrictive or permissive, or with the ins and outs of the Liskov Substitution Principle or other SOLID principle. This discussion is interesting, but the objective answer to the question is absolutely simple: it violates because it violates; violates because standard requires that the signatures are not different ...

In short: the code violates strict standards because one of the strict standards defines that " the signature of the methods in a class hierarchy needs to be identical ".

Now, if the question is "Why did you define a standard like this?", that is, why did you decide to include this requirement for identical signatures between strict standards? - then the focus is another.

Was it a good decision? Was it a bad decision? Who made that decision? For what reason? What can this restriction do?

I think an argument in favor would look something like this: "Within the strict standard, it is possible to know whether a parameter is valid or not for a method of a given hierarchy, regardless of the specific class of the object instance whose method is being invoked "- so the program would know if $hyperDate is a valid parameter for SetDate or not, even without using reflection and conditionals.

What is valid for one is valid for all. What is not valid for one, is not valid for any other. Whether it is parent or child .

How important is "knowing whether or not a parameter is valid for a method, regardless of the specific class of an instance"? How useful is it to require such consistency and uniformity in signing the method across a class hierarchy?

I do not know if it's important or even useful ... I know it's strict .

    
20.02.2014 / 03:23
0

The most convenient solution in this scenario would be.

interface  StdDate{ }

abstract class SuperDate {}

class SubDate extends SuperDate implements StdDate {}

class Foo
{
    public function setDate(StdDate $date) {}
}

class Bar extends Foo
{
    public function setDate(StdDate $date){}
}

$foo = new Foo();
$bar = new Bar();
$bar->setDate(new SubDate());
$foo->setDate(new SubDate());
    
23.02.2014 / 18:44