Can parameter types be specialized in PHP

Say we've got the following two classes:

abstract class Foo {
    public abstract function run(TypeA $object);
}

class Bar extends Foo {
    public function run(TypeB $object) {
        // Some code here
    }
}

The class TypeB extends the class TypeA.

Trying to use this yields the following error message:

Declaration of Bar::run() must be compatible with that of Foo::run()

Is PHP really this broken when it comes to parameter types, or am I just missing the point here?

Answers


The behavior you describe is called covariance and is simply not supported in PHP. I don't know the internals but I might suspect that PHP's core does not evaluate the inheritance tree at all when applying the so called "type hint" checks.

By the way, PHP also doesn't support contravariance on those type-hints (a feature commonly support in other OOP languages) - most likely to the reason is suspected above. So this doesn't work either:

abstract class Foo {
    public abstract function run(TypeB $object);
}

class Bar extends Foo {
    public function run(TypeA $object) {
        // Some code here
    }
}

And finally some more info: http://www.php.net/~derick/meeting-notes.html#implement-inheritance-rules-for-type-hints


This seems pretty consistent with most OO principals. PHP isn't like .Net - it doesn't allow you to override class members. Any extension of Foo should slide into where Foo was previously being used, which means you can't loosen constraints.

The simple solution is obviously to remove the type constraint, but if Bar::run() needs a different argument type, then it's really a different function and should ideally have a different name.

If TypeA and TypeB have anything in common, move the common elements to a base class and use that as your argument constraint.


I think this is by design: It is the point of abstract definitions to define the underlying behaviour of its methods.

When inheriting from an abstract class, all methods marked abstract in the parent's class declaration must be defined by the child; additionally, these methods must be defined with the same (or a less restricted) visibility.


One could always add the constraint in code:

public function run(TypeA $object) {
    assert( is_a($object, "TypeB") );

You'll have to remember or document the specific type limitation then. The advantage is that it becomes purely a development tool, as asserts are typically turned off on production servers. (And really this is among the class of bugs to be found while developing, not randomly disrupt production.)


Although you cannot use whole class-hierarchies as type-hinting. You can use the self and parent keywords to enforce something similar in certain situations.

quoting r dot wilczek at web-appz dot de from the PHP-manual comments:

<?php
interface Foo 
{
    public function baz(self $object);
}

class Bar implements Foo
{
    public function baz(self $object)
    {
        // 
    }
}
?>

What has not been mentioned by now is that you can use 'parent' as a typehint too. Example with an interface:

<?php
interface Foo 
{
    public function baz(parent $object); 
}

class Baz {}
class Bar extends Baz implements Foo
{
    public function baz(parent $object)
    {
        // 
    }
}
?>

Bar::baz() will now accept any instance of Baz. If Bar is not a heir of any class (no 'extends') PHP will raise a fatal error: 'Cannot access parent:: when current class scope has no parent'.


Need Your Help

yii2 gridview column headers not translated

php gridview widget yii2

Currently a problem with getting the headers translated when using the GridView Widget, supplied by Yii themselves.

MailChimp API V2 Need Help Regarding Templates

api templates mailchimp

I am using the REST based MailChimp API version 2.0. I am trying to create a campaign using the campaigns/create API method. I have a template that I designed using the built in designer. In the re...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.