Php static class interface

Php abstract classes and interfaces involving static methods

The new definition of is «sub-class must implement code for this specific class or any of its sub-classes». Solution 1: In most languages, including PHP, you cannot require a class to implement static methods.

Php abstract classes and interfaces involving static methods?

In most languages, including PHP, you cannot require a class to implement static methods.

This means neither class inheritance, nor interfaces, will allow you to require all implementors define a static method. This is probably because these features are designed to support polymorphism rather than type definition. In the case of static methods you’ll never have an object to resolve the type from, so would have to do ClassName::Method explicitly, so the theory is you wouldn’t gain anything from polymorphism.

As such, I see three solutions

  1. Declaring the static methods in each class (after all, you are never going to
  2. If you want a method to create instances of your class, but don’t want to require an instance to call this method, you could create «Builder» classes to serve this purpose (e.g. OrderBuilder ), such that you instantiate an OrderBuilder and call the Create method on this object instead to get Order instances.
  3. (Recommended) Why aren’t you simply using the Order constructor?
Читайте также:  Php перехват фатальных ошибок

After the comment from @hvertous, I decided to test this out. Using 3v4l we can see that abstract public static method :

Which confirms that it was removed in PHP 5.2, but if you are using PHP 7+ you can once again use abstract static methods.

Original answer

Yes, abstract static methods were removed in PHP 5.2. Apparently they were an oversight. See Why does PHP 5.2+ disallow abstract static class methods?.

However, you can have static methods in an interface, see this comment on php.net.

The problem you face is that you want your implementations to have different function signatures, which means that you probably shouldn’t be using inheritance to solve your problem.

Why does PHP 5.2+ disallow abstract static class methods?, Given this, abstract static methods in PHP 5.2 were useless. The entire point of using an abstract method is that you can write code that calls

Abstract classes with static methods in PHP

Performance is not even the biggest problem here, secret dependencies and lying APIs are.

From a testable point of view, static methods are awful, because they usually represent global state, which, surprisingly, is awful as well, because it means if you run a function two times, you can get different results even when the inputs are the same (that is what global state does). How do you test that?

I cannot really see any case, where I would prefer static methods instead of normal ones. If you can, do not use them, if you must use them, your design is most likely wrong and needs refactoring.

Check Clean Code Talks by Miško Hevery from 2008, they are still relevant and provide great explanations on why static methods and singletons should be avoided.

Some youtube references to some talks by Miško Hevery:

  • Global State and Singletons
  • Inheritance, Polymorphism, & Testing
  • How to Write Clean, Testable Code

Abstract Static Function in PHP 5.3, abstract class Table < protected abstract static function get_fields(); protected abstract static function get_primary_key(); protected abstract static function

Instance child class in abstract static method

First of all $template_name should be static , if you want to use it from a static method.

You can use late static bindings to access static methods and fields from the parent class:

Get(); > public static function get_template() < return static::$template_name; >> class HomeViews extends Views < protected static $template_name = 'home.html'; protected function Get() < echo self::get_template() . "\n"; var_dump($this); >> HomeViews::as_view(); /* outputs: home.html object(HomeViews)#1 (0) < >*/ 

Why can’t PHP traits have static abstract methods?

TL;DR: As of PHP 7, you can. Before then, you could define abstract static on trait , but internals deemed it bad practice.

Strictly, abstract means sub-class must implement, and static means code for this specific class only. Taken together, abstract static means «sub-class must implement code for this specific class only». Totally orthogonal concepts.

But. PHP 5.3+ supports static inheritance thanks to LSB. So we actually open that definition up a bit: self takes the former definition of static, while static becomes «code for this specific class or any of its sub-classes». The new definition of abstract static is «sub-class must implement code for this specific class or any of its sub-classes». This can lead some folks, who think of static in the strict sense, to confusion. See for example bug #53081.

What makes trait so special to elicit this warning? Well, take a look at the engine code that implements the notice:

That code says the only place an abstract static is allowed is within an interface . It’s not unique to traits, it’s unique to the definition of abstract static . Why? Well, notice there’s a slight corner case in our definition:

sub-class must implement code for this specific class or any of its sub-classes

That definition means I should be able to call Foo::get . After all Foo is a class (see that keyword «class» there) and in the strict definition, get is meant to be implemented in that class Foo . But clearly that makes no sense, because well, we’re back to the orthogonality of strict static.

If you try it in PHP, you get the only rationale response possible:

Cannot call abstract method Foo::get()

So because PHP added static inheritance, it has to deal with these corner cases. Such is the nature of features. Some other languages (C#, Java, etc.) don’t have this problem, because they adopt the strict definition and simply don’t allow abstract static . To get rid of this corner case, and simplify the engine, we may enforce this «abstract static only in interface» rule in the future. Hence, E_STRICT .

I would use a service delegate to solve the problem:

I have common method I want to use in several classes. This common method relies on a static method that must be defined externally to the common code.

trait MyTrait < public function doSomethingWithSetting() < $service = new MyService($this); return $service->doSomethingWithSetting(); > > class MyService < public function __construct(MyInterface $object) < $this->object = $object; > public function doSomethingWithSetting() < $setting = $this->object->getSetting(); return $setting; > > 

Feels a bit Rube Goldberg though. Probably would look at the motivation for statics and consider refactoring them out.

Php abstract classes and interfaces involving static methods?, This answer is incorrect. Interfaces and abstract classes can require descendants to implement static methods. – tvanc. May 13, 2019 at 18:31.

Источник

Возвращаемый тип self и static в интерфейсах PHP

Очень популярная история в PHP, когда метод объекта возвращает сам объект или новый экземпляр того же самого объекта. В этом случае мы указываем тип результата self и всё отлично работает. Например:

final class Car < public function __construct( private ?string $color = null, ) < >public function withColor(string $color): self < $new = clone $this; $new->color = $color; return $new; > >

С финальными классами это действительно гарантированно работает. Но в случае с интерфейсами (а также с не финальными классами, абстрактными классами и трейтами, но в этой статьей рассмотрим только интерфейсы) появляется не очевидная на первый взгляд проблема.

Проблема с self

Допустим у нас есть два интерфейса. Объекты, которые их реализуют, позволяют указать цвет и имя соответственно:

interface ColorableInterface < public function setColor(string $color): self; >interface NameableInterface

И мы решили сделать некий конфигуратор для объектов, реализующих оба интерфейса:

final class Configurator < public function configure( ColorableInterface&NameableInterface $object, string $color, string $name ): void < $object->setColor($color)->setName($name); > >

И вроде бы всё хорошо, но если прогнать этот код, к примеру, через статический анализатор Psalm, то мы получим ошибку «Method ColorableInterface::setName does not exist» («Метод ColorableInterface::setName не существует»).

И действительно, Psalm не ошибся. Интерфейс ColorableInterface гарантирует, что метод setColor() вернёт self , то есть объект, реализующий ColorableInterface , и ничего более, а метода setName() в интерфейсе ColorableInterface нет.

Пример объекта, реализующего оба интерфейса, но при этом не готового для использования в конфигураторе из предыдущего примера:

final class CustomColor implements ColorableInterface < private string $color = ''; public function setColor(string $color): self < $this->color = $color; return $this; > > final class CustomName implements NameableInterface < private string $name = ''; public function setName(string $name): self < $this->name = $name; return $this; > > final class StrangeObject implements ColorableInterface, NameableInterface < public function setColor(string $color): ColorableInterface < return new CustomColor(); >public function setName(string $name): NameableInterface < return new CustomName(); >>

Возвращаемый тип static

В PHP 8.0 появилась возможность указать в качестве результата выполнения метода тип static , который на уровне языка гарантирует, что метод вернёт экземпляр того же самого класса, в котором он вызван.

Теперь мы можем переписать интерфейсы следующим образом:

interface ColorableInterface < public function setColor(string $color): static; >interface NameableInterface

И это решит описанную выше проблему.

Когда использовать static?

Как правило, static используется в следующих ситуациях.

Текучие интерфейсы

Текучий интерфейс — структурный шаблон проектирования, позволяющий создавать более читабельный код. Фактически, это возможность вызова методов «цепочкой».

Неизменяемые классы

Неизменяемый (иммутабельный) класс — это класс, который после создания не меняет своего состояния, то есть он не содержит сеттеров и публичных изменяемых свойств. Но такие классы могут содержать методы (обычно они имеют префикс with ), позволяющие получить клон объекта с изменённым состоянием. Как раз для таких методов в интерфейсах необходимо использовать тип static .

interface ReadableInterface

Порождающие статические методы

Статические методы, позволяющие создать экземпляр объекта текущего класса.

Интерфейсы для «одиночек»

Интерфейс, определяющий метод для реализации шаблона проектирования «Одиночка» (метод предоставляющий доступ к единственному экземпляру объекта в приложении и запрещающий повторное создание этого объекта).

Заключение

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

  • self — любой объект, который реализует данный интерфейс;
  • static — экземпляр объекта того же класса, что и объект в котором вызван метод.

Источник

Оцените статью