Почему PHP допускает абстрактные статические функции

Рассмотрим следующий код:

abstract class ExampleClass
{
public static function regularStaticFunction()
{
return static::abstractStaticFunction();
}

abstract protected static function abstractStaticFunction();
}

ExampleClass::regularStaticFunction();

IDE PhpStorm помещает предупреждение в декларацию abstractStaticFunction что гласит:

Строгие стандарты PHP: Статическая функция abstractStaticFunction не должна быть абстрактной.

Статическая функция не должна быть абстрактной.

Тем не менее, PHP продолжает выполнение программы при анализе этого класса и выводит следующее:

Строгие стандарты PHP: Статическая функция ExampleClass :: abstractStaticFunction () не должна быть абстрактной в коде оболочки php в строке 7

Мне кажется, что поскольку PHP допускает вызовы статических функций в абстрактных классах, определение абстрактной статической функции в абстрактном классе не должно быть возможным.

Почему абстрактные статические функции разрешены в PHP интерпретатором, если они бессмысленны?

7

Решение

Это хорошее объяснение от этот ответ от Марк Эмери:

Отчет об ошибках PHP 53081, называется
для предупреждения, которое будет снято с момента добавления
static::foo() конструкция сделала разумными абстрактные статические методы
и полезно. Расмус Лердорф (создатель PHP) начинает с маркировки
просьба как фальшивая и проходит через длинную цепочку дурных рассуждений
попытаться оправдать предупреждение. Затем, наконец, происходит этот обмен:

Джорджио

я знаю, но:

abstract class cA
{
//static function A(){self::B();} error, undefined method
static function A(){static::B();} // good
abstract static function B();
}

class cB extends cA
{
static function B(){echo "ok";}
}

cB::A();

Расмус

Правильно, именно так оно и должно работать.

Джорджио

но это не разрешено 🙁

Расмус

Что не разрешено?

abstract class cA {
static function A(){static::B();}
abstract static function B();
}

class cB extends cA {
static function B(){echo "ok";}
}

cB::A();

Это отлично работает. Вы, очевидно, не можете вызвать self :: B (), но static :: B ()
Это хорошо.

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

И именно поэтому предупреждение все еще на языке. Это не может быть
вполне удовлетворительное объяснение — вы, вероятно, пришли сюда в надежде
было рациональное обоснование предупреждения. К сожалению, в
в реальном мире, иногда выбор рождается из мирских ошибок и
плохие рассуждения, а не от рационального принятия решений. Это
просто один из тех времен.

К счастью, респектабельный Никита Попов снял предупреждение с
язык в PHP 7 как часть PHP RFC: реклассифицировать E_STRICT
уведомления
. В конечном счете,
здравый смысл возобладал, и когда выйдет PHP 7, мы все сможем счастливо
использование abstract static без получения этого глупого предупреждения.

18

Другие решения

Абстрактные статические функции не являются бессмысленными! На самом деле, они позволяют использовать некоторые конструкции, которые, на мой взгляд, проще и чище, чем то, к чему я должен был бы прибегнуть в языке, в котором их нет, например в Java или C #.

Давайте возьмем пример. Предположим, я пишу какое-то обычное корпоративное бизнес-приложение, которое должно синхронизировать некоторые бизнес-объекты между двумя API. Эти API имеют объектные модели, которые можно сопоставлять друг с другом, но использовать разные имена и разные форматы сериализации.

В PHP, благодаря абстрактным статическим методам, я могу определить абстрактный базовый класс для этих типов бизнес-объектов, который выглядит следующим образом …

abstract class ApiObject {
/** The REST resource URL for this object type in the Foo API. */
abstract static function fooApiResourceUrl();

/** The REST resource URL for this object type in the Bar API. */
abstract static function barApiResourceUrl();

/** Given an XML response from the Foo API representing an object of this
type, construct an instance. */
abstract static function fromFooXml($xml);

/** Given a JSON response from the Bar API representing an object of this
type, construct an instance. */
abstract static function fromBarJson($json);

/** Serialize this object in the XML format that the Foo API understands */
abstract function toFooXml();

/** Serialize this object as JSON that the Bar API understands */
abstract function toBarJson();
}

… и тогда каждый конкретный подкласс, который я создаю, будет гарантированный предоставить всю информацию, необходимую для извлечения ее из любого из двух API и десериализации, или для ее сериализации и отправки в любой API. Затем, позже, я могу написать такой код:

// Ensure that all instances of these types that exist in the Foo API also
// exist in the Bar API:
$classesToSync = ['Widget', 'Frobnicator', 'Lead', 'Invoice'];
foreach ($classesToSync as $apiObjectClass) {
$fooObjXmls = httpGetRequest($apiObjectClass::fooApiResourceUrl());
foreach ($fooObjXmls as $fooObjXml) {
$fooObj = $apiObjectClass::fromFooXml($fooObjXml);
$json = $fooObj->toBarJson();
httpPutRequest($apiObjectClass::barApiResourceUrl(), $json);
}
}

Я строго необходимость абстрактные статические методы для написания программы выше? Нет; есть и другие шаблоны, которые я мог бы использовать, например, связать каждый класс модели с соответствующим классом фабрики, который отвечает за создание его экземпляра из его представлений JSON или XML. Но такой дизайн сложнее, чем тот, который я показал выше.

Ответ на то, почему им позволено, состоит в том, что они просто полезным, так как они допускают некоторые хорошие, простые шаблоны, которые были бы невозможны без них. Конечно, есть и аргументы против они существуют, один из которых был задан в вопросе — что некрасиво выставлять абстрактные статические методы в классе, учитывая, что статические методы в абстрактном классе могут быть вызваны. Я не считаю такие соображения особенно убедительными, но даже если вы это сделаете, между ними и утилитой, предоставляемой абстрактными статическими методами, все еще есть компромисс, и разработчики PHP предположительно взвесили их и выбрали сторону предоставления абстрактных статических методов. существовать.

0