Декларація методів має бути сумісною з батьківськими методами в PHP


107
Суворі стандарти: Декларація childClass :: customMethod () має бути сумісною з дозволом parentClass :: customMethod ()

Які можливі причини цієї помилки в PHP? Де я можу знайти інформацію про те, що означає бути сумісним ?


notJim має це правильно. @ waiwai933, якщо ви можете опублікувати заголовки (лише перший рядок function customMethod( ... )
:)

Більш детально про повідомлення про помилку та значення PHP для збирання часу: bugs.php.net/bug.php?id=46851
hakre


1
Моя проблема полягала в тому, що аргумент натякнув тип, але потім я не додав use Closure;до верхнього класу (оскільки тип-підказка був Closure). Отже ... не забудьте перевірити, чи не вистачає вам таких залежностей.
Райан

Відповіді:


126

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


1
Можливо, це тому, що видимість , підпис методів не є проблемою в PHP
Габріель Соса

43
Маючи однакові точні значення аргументу також важливі. Наприклад, parentClass::customMethod($thing = false)і childClass::customMethod($thing)призведе до помилки, оскільки метод дитини не визначив значення за замовчуванням для першого аргументу.
Чарльз

1
Я вважаю, що видимість насправді є різною помилкою. До речі, в моєму магазині ми не використовуємо суворий режим через це (ми використовуємо E_ALL, IIRC).
davidtbernal

12
Це змінилося в PHP 5.4, btw: * E_ALL тепер включає помилки рівня E_STRICT в директиві конфігурації error_reporting. Дивіться тут: php.net/manual/en/migration54.other.php
Замок Дункана

1
Відсутність &аргументу ampersand ( ) може також викликати цю помилку.
IvanRF

36

Це повідомлення означає, що існують певні можливі виклики методів, які можуть не працювати під час виконання. Припустимо, у вас є

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) {;}}

Це здається більш обмежуючим, ніж це потрібно, і я припускаю, що це пов'язано з внутрішніми.

Різниці в видимості викликають різну помилку, але з тієї ж основної причини. Жоден метод не може бути менш помітним, ніж його батьківський метод.


2
у вашому останньому прикладі - тут не повинно бути помилок, оскільки це законно, stdClass $ a є більш обмежувальним, ніж змішаний $ a. чи є спосіб обійти це? Я маю на увазі в цьому випадку PHP повинен дозволити це, але він все одно дає помилку ...
galchen

2
Ваш останній приклад є безпечним для типу, тому він, безумовно, є "більш обмежуючим, ніж потрібно". Це може бути випадок
групового

дякую за пояснення, в моєму випадку перший приклад, який ви навели, був саме тим, що викликало мою помилку.
billynoah

Дякую за це, сер.
Eldoïr

22

якщо ви хочете зберегти форму OOP без вимкнення помилок, ви також можете:

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

    }
}

Я хотів би використовувати цей злом, щоб обійти ці помилки. Я хвилююся, що за цей підхід може бути покарання за ефективність? Я досліджу це, але якщо у вас є ресурси, які допоможуть відповісти на це питання, це було б чудово.
Адам Фрідман

Я думаю, залежно від ситуації. Все-таки Так, це може бути трохи хакі, але це php? вже, іноді це може бути приємною роботою, спасибі! <@
Майстер Джеймс

ти врятував мій день! це був єдиний варіант запуску застарілого проекту php5 на сервері з php7 без болю
vladkras

В цьому випадку ви можете використовувати значення за замовчуванням , замість того func_get_args(), тобто, в B, public function foo($a = null, $b = null, $c = null)як це не порушує контракт , обіцяний A.
Джейк

1

Просто для розширення цієї помилки в контексті інтерфейсу, якщо ви вводите натяк на параметри функції, як-от так:

інтерфейс A

use Bar;

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

Клас В

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

Якщо ви забули включити useоператор до свого класу реалізації (клас B), ви також отримаєте цю помилку, навіть якщо параметри методу однакові.


0

Я зіткнувся з цією проблемою, намагаючись розширити існуючий клас від 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();
   }
}

Отже, замість того, щоб намагатися використовувати метод "що завгодно", я написав новий під назвою "getWever". Насправді вони обидва роблять те саме, просто повертаючи клас, але з просторами імен різних, як я описав раніше.

Сподіваюся, це може комусь допомогти.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.