Декларація методів має бути сумісною з батьківськими методами в 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.