Объявление методов должно быть совместимо с родительскими методами в PHP

Строгие стандарты: объявление childClass::customMethod() должно быть совместимо с таковым для parentClass::customMethod()

Каковы возможные причины этой ошибки в PHP? Где я могу найти информацию о том, что значит быть совместимым?

4 ответа

Решение

childClass::customMethod() имеет разные аргументы или другой уровень доступа (публичный / частный / защищенный), чем parentClass::customMethod(),

Это сообщение означает, что существуют определенные возможные вызовы методов, которые могут не работать во время выполнения. Предположим, у вас есть

class A { public function foo($a = 1) {;}}
class B extends A { public function foo($a) {;}}
function bar(A $a) {$a->foo();}

Компилятор только проверяет вызов $a->foo() на соответствие требованиям A::foo(), который не требует параметров. Однако $ a может быть объектом класса B, для которого требуется параметр, и поэтому вызов не будет выполнен во время выполнения.

Это однако никогда не может потерпеть неудачу и не вызывает ошибку

class A { public function foo($a) {;}}
class B extends A { public function foo($a = 1) {;}}
function bar(A $a) {$a->foo();}

Таким образом, ни один метод не может иметь больше обязательных параметров, чем его родительский метод.

Это же сообщение также генерируется, когда подсказки типа не совпадают, но в этом случае PHP является еще более ограничительным. Это дает ошибку:

class A { public function foo(StdClass $a) {;}}
class B extends A { public function foo($a) {;}}

как это:

class A { public function foo($a) {;}}
class B extends A { public function foo(StdClass $a) {;}}

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

Различия в видимости вызывают другую ошибку, но по той же основной причине. Ни один метод не может быть менее видимым, чем его родительский метод.

Если вы хотите сохранить форму ООП, не отключая ошибки, вы также можете:

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

    }
}

Просто чтобы раскрыть эту ошибку в контексте интерфейса, если вы набираете тип, намекая на параметры вашей функции, например, так:

интерфейс А

use Bar;

interface A
{
    public function foo(Bar $b);
}

Класс б

class B implements A
{
    public function foo(Bar $b);
}

Если вы забыли включить use оператора вашего класса реализации (класса B), вы также получите эту ошибку, даже если параметры метода идентичны.

Я столкнулся с этой проблемой при попытке расширить существующий класс из GitHub. Я попытаюсь объяснить себя, сначала напишу класс так, как я думал, что он должен быть, а затем класс, как он есть сейчас.

Что я хотя

namespace mycompany\CutreApi;

use mycompany\CutreApi\ClassOfVendor;

class CutreApi extends \vendor\AwesomeApi\AwesomeApi
{
   public function whatever(): ClassOfVendor
   {
        return new ClassOfVendor();
   }
}

Что я наконец сделал

namespace mycompany\CutreApi;

use \vendor\AwesomeApi\ClassOfVendor;

class CutreApi extends \vendor\AwesomeApi\AwesomeApi
{
   public function whatever(): ClassOfVendor
   {
        return new \mycompany\CutreApi\ClassOfVendor();
   }
}

Кажется, что эта ошибка возникает также, когда вы используете метод, который возвращает класс с пространством имен, и вы пытаетесь вернуть тот же класс, но с другим пространством имен. К счастью, я нашел это решение, но я не совсем понимаю преимущества этой функции в php 7.2, для меня нормально переписывать существующие методы класса по мере необходимости, включая переопределение входных параметров и / или даже поведения метод.

Одним из недостатков предыдущего подхода является то, что среда IDE не могла распознать новые методы, реализованные в \mycompany\CutreApi\ClassOfVendor(). Итак, пока я перейду к этой реализации.

В настоящее время сделано

namespace mycompany\CutreApi;

use mycompany\CutreApi\ClassOfVendor;

class CutreApi extends \vendor\AwesomeApi\AwesomeApi
{
   public function getWhatever(): ClassOfVendor
   {
        return new ClassOfVendor();
   }
}

Итак, вместо того, чтобы пытаться использовать "любой" метод, я написал новый под названием "getWhatever". На самом деле они оба делают то же самое, просто возвращая класс, но с разными пространствами имен, как я описывал ранее.

Надеюсь, это кому-то поможет.

Абстрактный класс А

abstract class A {
    function foo();
}

Детский класс B

class B {
    function foo($a=null, $b=null, $c=null)
    {
        //do what you want with the parameters.
    }
}

Пример:

$b = new B();
$b->foo();
$b->($m, $n, $l);

Цель состоит в том, чтобы сделать оба $b->foo а также $b->($m, $n, $l) хорошо работать.

Другие вопросы по тегам