Могут ли типы параметров быть специализированными в PHP? - PullRequest
3 голосов
/ 29 декабря 2010

Скажем, у нас есть два следующих класса:

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

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

Класс TypeB расширяет класс TypeA.

Попытка использовать это приводит к следующему сообщению об ошибке:

Объявление Bar :: run () должно быть совместимо с таковым для Foo :: run ()

Действительно ли PHP не работает, когда дело доходит до типов параметров, или я просто упускаю суть здесь?

Ответы [ 5 ]

6 голосов
/ 29 декабря 2010

Поведение, которое вы описываете, называется ковариация и просто не поддерживается в PHP. Я не знаю внутренностей, но я могу подозревать, что ядро ​​PHP вообще не оценивает дерево наследования при применении так называемых проверок «подсказки типа».

Кстати, PHP также не поддерживает контравариантность для этих подсказок (функция, обычно поддерживаемая в других языках ООП) - скорее всего, причина подозревается выше , Так что это тоже не работает:

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

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

И, наконец, еще немного информации: http://www.php.net/~derick/meeting-notes.html#implement-inheritance-rules-for-type-hints

2 голосов
/ 29 декабря 2010

Это, кажется, довольно согласуется с большинством ОО принципалов. PHP не похож на .Net - он не позволяет переопределять членов класса. Любое расширение Foo должно попасть туда, где ранее использовалось Foo, что означает, что вы не можете ослабить ограничения.

Очевидно, что простым решением является удаление ограничения типа, но если Bar::run() нужен другой тип аргумента, то это действительно другая функция и в идеале должно иметь другое имя.

Если у TypeA и TypeB есть что-то общее, переместите общие элементы в базовый класс и используйте это в качестве ограничения аргумента.

0 голосов
/ 29 декабря 2010

Хотя вы не можете использовать целые иерархии классов в качестве подсказки типа. Вы можете использовать ключевые слова self и parent, чтобы применить нечто подобное в определенных ситуациях.

цитирование r dot wilczek в web-appz dot de из комментариев к PHP-руководству:

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

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

Что сейчас не упоминалось, так это то, что вы также можете использовать «родитель» в качестве шрифта. Пример с интерфейсом:

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

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

Bar :: baz () теперь будет принимать любой экземпляр Baz. Если Бар не является наследником какого-либо класса (не «расширяет»), PHP выдаст фатальную ошибку: «Невозможно получить доступ к parent ::, если у текущего класса нет родителя».

0 голосов
/ 29 декабря 2010

Всегда можно добавить ограничение в коде:

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

Тогда вам придется запомнить или задокументировать ограничение конкретного типа.Преимущество состоит в том, что он становится просто инструментом разработки, поскольку утверждения обычно отключаются на производственных серверах.(И действительно, это одна из тех ошибок, которые можно обнаружить при разработке, а не случайное нарушение работы.)

0 голосов
/ 29 декабря 2010

Я думаю, что это по замыслу : Это точка абстрактных определений, чтобы определить базовое поведение его методов.

При наследовании от абстрактного класса все методы, помеченные как абстрактные в объявлении класса родителя, должны быть определены дочерним объектом; Кроме того, эти методы должны быть определены с одинаковой (или менее ограниченной) видимостью.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...