Why does this violate Strict Standards?

Asked

Viewed 157 times

5

take into account the following definitions of classes:

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 cause is the signature of Bar::setDate be different from Foo:setDate. Stackoverflow in English has a similar question which refers to a violation of The Liskov Substitution Principle as the cause of "Strict Warning", but the situation is slightly different because the subclass is more restrictive than the mother class.

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

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

  • Related: http://answall.com/questions/2413

  • Maybe because the guy in Bar is not set? Tried Object?

  • @bfavaretto Gives the same error.

  • @bfavaretto I edited to clarify the problem better

3 answers

2


The child class method parameter has to be exactly the same as the parent class method parameter.

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

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

In programs with strong typing, when making a override a method of Foo, if you change the signature of Bar, you’re actually making a Overload, since the original method and the new method have different signatures. However, since PHP has weak typing, this is not possible to achieve, since the compiler does not know which of the methods you are actually calling (so the reason why you cannot have two methods with the same name, even if your signatures are different).

Then, in order to prevent the violation of the principle of Liskov’s replacement, a warning Strict standard is done by warning the programmer that there is a potential problem due to the change in the signature of the child class method.

(translated from: https://stackoverflow.com/questions/13423494/why-is-overriding-method-parameters-a-violation-of-strict-standards-in-php)

I mean, 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) {}
}
  • Yeah, but my question is, why does it have to be this way?!

  • For when you inherit methods from a superclass, when you overwrite them you need to pass the same arguments that the higher method requires.

  • I changed the answer, see if it answers your question.

  • How so the compiler does not know which of the methods you are actually calling?

  • What I understood was: if it existed overloading in PHP, due to the weak typing feature of the language, the compiler would not know which method to actually call.

  • 3

    :-) That was good... the answer you translated and includes here who wrote was the author of the question himself!

Show 1 more comment

2

I think the answer to this question is very simple.

That code violates the standard because the standard is Strict (restricted), and in its strict definition of compatible (compatible), the signature of the methods must be identical.

This is the standard. So that’s why this code violates the standard: because the standard requires signatures to be identical. And full stop.

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

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


Now, if the question is "why have you defined a standard like this?", I mean, "why did you decide to include this requirement of identical signatures among the Strict standards?" - then the focus is elsewhere.

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

I think a favor argument would look something like this: "within the strict pattern, it is possible to know whether a parameter is valid or not for a method of a given hierarchy, whatever is the specific class of the instance of the object whose method is being invoked" - thus the programme would have a way of knowing whether $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. Independent of being parent or child.

How important is it "to know if a parameter is valid or not for a method, whatever the specific class of an instance"? How useful it is to require this consistency and uniformization in the signature of the method across a class hierarchy?

I don’t know if it’s important or even useful... I know it’s Strict.

  • Do you have a link to the list of definitions of Strict standards? I think it’s the only thing missing in your answer.

  • I don’t. I just got the information from the error message: Strict standards: Declaration of Bar::setDate() should be compatible with Foo::setDate(DateTime $date) - and the links shared here. I don’t know what the others are.

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());

Browser other questions tagged

You are not signed in. Login or sign up in order to post.