PHP Неустранимая ошибка: не удается наследовать абстрактную функцию

Я не понимаю, что я делаю неправильно...

abstract class Css {
    abstract protected function parse($data);
}

abstract class CssElem extends Css {
    abstract protected function parse($data);
}

class Modifier extends CssElem {
    function __construct($data = null) {
        if( $data )
            $this->parse ($data);
    }

    protected function parse($data) {
       // Some code...
    }
}

Это дает мне:

[Mon Jul 8 13:21:10 2013] PHP Неустранимая ошибка: не удается наследовать абстрактный функция Css:: parse() (ранее объявленная абстракция в CssElem) в /home/arthur/NetBeansProjects/capa/CssElem.php в строке 21 [Пн Июл 8 13:21:10 2013] 127.0.0.1:41207 [500]:/- Не удается наследовать абстрактный функция Css:: parse() (ранее объявленная абстракция в CssElem) в /home/arthur/NetBeansProjects/capa/CssElem.php в строке 21

Строка 21 - это abstract protected function parse($data); в CssElem.

Я больше знаком с ООП на Java, но он выглядит нормально в соответствии с документом...

Ответ 1

Попробуйте изменить свой промежуточный класс на:

abstract class CssElem extends Css {
    // abstract protected function parse($data); // <-- take this away
}

См. также этот комментарий в документах.

Цитата из комментария:

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

Кажется, что это будет разрешено в следующем PHP версии 7.2:

Теперь разрешено переопределять абстрактный метод другим абстрактным методом в дочернем классе. (https://wiki.php.net/rfc/allow-abstract-function-override)

Ответ 2

Ответ Патрика Хай был определенно полезен.

Эта ошибка описана здесь:
https://bugs.php.net/bug.php?id=43200
Как отмечено там, ошибка имеет значение, если вы хотите расширить устаревшие интерфейсы.

Он может быть воспроизведен на http://3v4l.org, показывая, что он исправлен с PHP 5.3.9.

Простейшая форма

Это может быть "исправлено" решением Matteo Tassinari, комментируя определение foo() во втором интерфейсе.

http://3v4l.org/qo6sG
5.0.0 - 5.3.8: Неустранимая ошибка: не удается наследовать абстрактную функцию A:: foo()
5.3.9 - *: Нет проблем.

interface A {
  function foo();
}

interface B extends A {
  function foo();
}

С добавленными необязательными параметрами

http://3v4l.org/ZXq0O
5.0.0 - 5.3.8: Неустранимая ошибка: не удается наследовать абстрактную функцию A:: foo()
5.3.9 - *: Нет проблем.

interface A {
  function foo();
}

interface B extends A {
  function foo($x = NULL);
}

С добавлением требуемых параметров

http://3v4l.org/5fPBO
5.0.0 - 5.3.8: Неустранимая ошибка: не удается наследовать абстрактную функцию A:: foo()
5.3.9 - *: Неустранимая ошибка: Декларация B:: foo() должна быть совместима с (A) A:: foo()

interface A {
  function foo();
}

interface B extends A {
  function foo($x);
}

(Мы не удивлены, это ломается во всех версиях PHP)

С добавлением дополнительных параметров в реализацию:

http://3v4l.org/UvcLA
5.0.0 - *: Нет проблем

/**
 * @legacy
 */
interface A {
    function foo();
}

/**
 * Supersedes legacy interface A
 */
interface B extends A {
    /**
     * @param int|null $x
     *   Optional parameter added in new version.
     */
    # function foo($x = NULL);
}

class C implements B {
    function foo($x = NULL) {}
}

Ответ 3

Недавно я столкнулся с этой проблемой. Для меня это помогло перейти с PHP 5.3.8 на PHP 5.3.28.

Я не знаю точно, когда произошло изменение, но в 5.3.28 можно переопределить методы интерфейса в абстрактных классах и по-прежнему унаследовать их.

Ответ 4

Вам не нужно снова объявлять свою абстрактную функцию, объявляйте только о ее реализации.

Когда вы расширяете Css на CssElem, функция parse объединяется. Когда вы реализуете CssElem, вы должны также реализовать функцию синтаксического анализа.