Why do we often hear that we have to use the "final" directive all over and always? Where does it come from in PHP and why this dogmatic statement should be assumed as a mistake in a PHP realm. Do we have to use a "final" directive within the PHP? In which cases it might be done, when it shouldn't and when it's obligate.
3. Программа
Состояние объекта. Mutable vs Immutable
Шаблон Immutable Object для многопоточности и запрет
наследования в нем
Карго-культ: бездумный перенос шаблона из многопоточности в
однопоточный PHP
Корректное использование final в PHP: IoC + LSP + final
5. Как надо использовать директиву final?
Вопрос на засыпку
1. как подсказывает твое сердце
2. везде и всегда, только final, только хардкор
3. руководствуясь здравым смыслом
8. Stateful & Stateless
Объекты с состоянием и без
Stateful
Cat
-name: string
-breed: Breed
-furColor: string
-dateOfBirth: DateTime
-weightGram: int
-health: Health
//methods ...
Actor
9. Stateful & Stateless
Объекты с состоянием и без
Stateful Stateless
Cat
-name: string
-breed: Breed
-furColor: string
-dateOfBirth: DateTime
-weightGram: int
-health: Health
//methods ...
Actor
CatFeedCalculator
//noProperties
+calculateBestFoodType(Cat $cat): CatFood
+calculatePortionWeightGrams(Cat $cat): int
+calcutateWeekFeedShedule(Cat $cat): Shedule
Logic operations
11. Stateful & Stateless
Объекты с состоянием и без
Stateful Stateless
Cat
-name: string
-breed: Breed
-furColor: string
-dateOfBirth: DateTime
-weightGram: int
-health: Health
//methods ...
CatFeedCalculator
//noProperties
+calculateBestFoodType(Cat $cat): CatFood
+calculatePortionWeightGrams(Cat $cat): int
+calcutateWeekFeedShedule(Cat $cat): Shedule
Logic operations
Actor
20. Stateful
Объекты с состоянием
Stateful
Thread_1 Thread_2
?
Где хвост?
Multithreading:
Конкурирующие потоки могут одновременно
работать с одним и тем же экземпляром класса
и МЕНЯТЬ его
Actor
21. Stateful
Объекты с состоянием
Stateful
Thread_1 Thread_2
?
Где хвост?
Ха-ха-ха
Multithreading:
Конкурирующие потоки могут одновременно
работать с одним и тем же экземпляром класса
и МЕНЯТЬ его
Actor
24. Immutable Object
Состояние объекта не может меняться после создания
Запретить изменение состояния
+setAnyData(...)
Oтсутствуют не только
сеттеры, но и любые
изменения состояния
объекта
Как это
делается
25. Immutable Object
Состояние объекта не может меняться после создания
+setAnyData(...) and Defensive Copying
Защитное копирование
для мутабельных
свойств объектов
Запретить изменение состояния
Отсутствуют не только
сеттеры, но и любые
изменения состояния
объекта
Как это
делается
26. Immutable Object
Состояние объекта не может меняться после создания
+setAnyData(...) and Defensive Copying
class IAmImmutable {
private $mutableTrash;
public function __construct(MutableTrash $mutableTrash) {
$this->mutableTrash = clone $mutableTrash;
}
public function getMutableTrash(): MutableTrash {
return clone $this->mutableTrash;
}
}
Запретить изменение состояния
Oтсутствуют не только
сеттеры, но и любые
изменения состояния
объекта
Защитное копирование
для мутабельных
свойств объектов
Как это
делается
28. Immutable Object
Состояние объекта не может меняться после создания
+setAnyData(...) and Defensive Copying
Запретить изменение состояния
Oтсутствуют не только
сеттеры, но и любые
изменения состояния
объекта
Защитное копирование
для мутабельных
свойств объектов
class IAmImmutable {
private $mutableTrash;
public function __construct(MutableTrash $mutableTrash) {
$this->mutableTrash = clone $mutableTrash;
}
public function getMutableTrash(): MutableTrash {
return clone $this->mutableTrash;
}
}
29. Immutable Object
Состояние объекта не может меняться после создания
Закрыть переопределение через Наследование
+setAnyData(...) and Defensive Copying
class IAmImmutable {
private $mutableTrash;
public function __construct(MutableTrash $mutableTrash) {
$this->mutableTrash = clone $mutableTrash;
}
public function getMutableTrash(): MutableTrash {
return clone $this->mutableTrash;
}
}
<<final>>
IAmImmutable
Запретить изменение состояния
Отсутствуют не только
сеттеры, но и любые
изменения состояния
объекта
Защитное копирование
для мутабельных
свойств объектов
<<interface>>
IAmInterface
30. Immutable Object
Состояние объекта не может меняться после создания
Закрыть переопределение через Наследование
+setAnyData(...) and Defensive Copying
final class IAmImmutable implements IAmInterface {
private $mutableTrash;
public function __construct(MutableTrash $mutableTrash) {
$this->mutableTrash = clone $mutableTrash;
}
public function getMutableTrash(): MutableTrash {
return clone $this->mutableTrash;
}
}
<<final>>
IAmImmutable
Запретить изменение состояния
Отсутствуют не только
сеттеры, но и любые
изменения состояния
объекта
Защитное копирование
для мутабельных
свойств объектов
<<interface>>
IAmInterface
31. Immutable Object
Состояние объекта не может меняться после создания
Запретить изменение состояния
Закрыть переопределение через Наследование
Зачем
32. Immutable Object
Состояние объекта не может меняться после создания
SeemsLikeImmutable
+doSomething(...)
Запретить изменение состояния
Закрыть переопределение через Наследование
Зачем
Not Final
33. Immutable Object
Состояние объекта не может меняться после создания
SeemsLikeImmutable
+doSomething(...)
//SeemsLikeImmutable client code:
public function useImmutable ( SeemsLikeImmutable $immutable) {
$immutable->doSomething();
}
Запретить изменение состояния
Закрыть переопределение через Наследование
Зачем
Not Final
34. Immutable Object
Состояние объекта не может меняться после создания
SeemsLikeImmutable
+doSomething(...)
EvilHeritor
+doSomething(...) // modifies internal state
Запретить изменение состояния
Закрыть переопределение через Наследование
Зачем
Not Final
//SeemsLikeImmutable client code:
public function useImmutable ( SeemsLikeImmutable $immutable) {
$immutable->doSomething();
}
35. Immutable Object
Состояние объекта не может меняться после создания
SeemsLikeImmutable
+doSomething(...)
EvilHeritor
+doSomething(...) // modifies internal state
Запретить изменение состояния
Закрыть переопределение через Наследование
Зачем
Not Final
//SeemsLikeImmutable client code:
public function useImmutable ( SeemsLikeImmutable $immutable) {
$immutable->doSomething();
}
36. Immutable Object
Состояние объекта не может меняться после создания
SeemsLikeImmutable
+doSomething(...)
EvilHeritor
//SeemsLikeImmutable client code:
public function useImmutable ( SeemsLikeImmutable $immutable) {
$immutable->doSomething();
}
Запретить изменение состояния
Закрыть переопределение через Наследование
Зачем
Not Final
+doSomething(...) // modifies internal state
37. Immutable Object
Состояние объекта не может меняться после создания
SeemsLikeImmutable
+doSomething(...)
EvilHeritor
//SeemsLikeImmutable client code:
public function useImmutable ( SeemsLikeImmutable $immutable) {
$immutable->doSomething();
}
Запретить изменение состояния
Закрыть переопределение через Наследование
Зачем
Mutable!
Not Final
+doSomething(...) // modifies internal state
38. Immutable Object
Состояние объекта не может меняться после создания
SeemsLikeImmutable
+doSomething(...)
EvilHeritor
//SeemsLikeImmutable client code:
public function useImmutable ( SeemsLikeImmutable $immutable) {
$immutable->doSomething();
}
Запретить изменение состояния
Закрыть переопределение через Наследование
Зачем
Mutable!
Not Final
+doSomething(...) // modifies internal state
Thread_2
Отрежу хвост!
39. Immutable Object
Состояние объекта не может меняться после создания
SeemsLikeImmutable
+doSomething(...)
EvilHeritor
//SeemsLikeImmutable client code:
public function useImmutable ( SeemsLikeImmutable $immutable) {
$immutable->doSomething();
}
Запретить изменение состояния
Закрыть переопределение через Наследование
Зачем
Mutable!
Not Final
+doSomething(...) // modifies internal state
Thread_2
Отрежу хвост!
LSP
violation risk
43. Immutable Object
Состояние объекта не может меняться после создания
- Усложнение архитектуры
+ Простые классы
+ Final+Multithread: помогает
избегать изменения состояния
объекта конкурирующими
потоками и связанными с этим
трудновоспроизводимыми
багами
Плюсы-минусы
44. Immutable Object
Состояние объекта не может меняться после создания
- Усложнение архитектуры
- Final сложен для понимания в
однопоточной среде
+ Простые классы
+ Final+Multithread: помогает
избегать изменения состояния
объекта конкурирующими
потоками и связанными с этим
трудновоспроизводимыми
багами
Плюсы-минусы
49. Карго культ в действии
Java PHP
- Рекомендации по проектированию собираются
из серьезных книг
50. Карго культ в действии
Java
- Большинство серьезных книг по дизайну пишут
джависты исходя из реалий Java
PHP
- Рекомендации по проектированию собираются
из серьезных книг
51. Карго культ в действии
Java
- Большинство серьезных книг по дизайну пишут
джависты исходя из реалий Java
- Реалии Java: Многопоточность
PHP
- Рекомендации по проектированию собираются
из серьезных книг
52. Карго культ в действии
Java
- Большинство серьезных книг по дизайну пишут
джависты исходя из реалий Java
- Реалии Java: Многопоточность
PHP
- Рекомендации по проектированию собираются
из серьезных книг
- Однопоточность
53. Карго культ в действии
Java
- Большинство серьезных книг по дизайну пишут
джависты исходя из реалий Java
- Реалии Java: Многопоточность
- Имеет строгие рекомендации закрывать всё
интерфейсами и финализировать
PHP
- Рекомендации по проектированию собираются
из серьезных книг
- Однопоточность
54. Карго культ в действии
Java
- Большинство серьезных книг по дизайну пишут
джависты исходя из реалий Java
- Реалии Java: Многопоточность
- Имеет строгие рекомендации закрывать всё
интерфейсами и финализировать
PHP
- Рекомендации по проектированию собираются
из серьезных книг
- Однопоточность
- Реалии PHP: исторически сложившаяся
“свобода” (не обязательно есть интерфейсы, не
всегда пишутся юнит-тесты)
55. Карго культ в действии
Java
- Большинство серьезных книг по дизайну пишут
джависты исходя из реалий Java
- Реалии Java: Многопоточность
- Имеет строгие рекомендации закрывать всё
интерфейсами и финализировать
PHP
- Рекомендации по проектированию собираются
из серьезных книг
- Однопоточность
- Реалии PHP: исторически сложившаяся
“свобода” (не обязательно есть интерфейсы, не
всегда пишутся юнит-тесты)
Все классы должны быть final
56. Карго культ в действии
Java
final class IAmImmutable implements IAmInterface { … }
PHP
57. Карго культ в действии
Java
final class IAmImmutable implements IAmInterface { … }
PHP
final class IAmImmutable implements IAmInterface { … }
или
final class IAmImmutable { … }
58. Карго культ в действии
Java
final class IAmImmutable implements IAmInterface { … }
PHP
final class IAmImmutable implements IAmInterface { … }
или
final class IAmImmutable { … }
Зачем тут нужна директива final?
59. Карго культ в действии
Java
final class IAmImmutable implements IAmInterface { … }
Final помогает решить конкретную
проблему гонки данных в условиях
многопоточности
PHP
final class IAmImmutable implements IAmInterface { … }
или
final class IAmImmutable { … }
Зачем тут нужна директива final?
60. Карго культ в действии
Java
final class IAmImmutable implements IAmInterface { … }
Final помогает решить конкретную
проблему гонки данных в условиях
многопоточности
PHP
final class IAmImmutable implements IAmInterface { … }
или
final class IAmImmutable { … }
“Ну чтобы другие разработчики
соблюдали дизайн”
Зачем тут нужна директива final?
61. Карго культ в действии
Java
final class IAmImmutable implements IAmInterface { … }
Final помогает решить конкретную
проблему гонки данных в условиях
многопоточности
PHP
final class IAmImmutable implements IAmInterface { … }
или
final class IAmImmutable { … }
“Ну чтобы другие разработчики
соблюдали дизайн”
Зачем тут нужна директива final?
62. Java
final class IAmImmutable implements IAmInterface { … }
Final помогает решить конкретную
проблему гонки данных в условиях
многопоточности
PHP
final class IAmImmutable implements IAmInterface { … }
или
final class IAmImmutable { … }
“Ну чтобы другие разработчики
соблюдали дизайн”
Runtime
error
prevention
Design
discussion
Карго культ в действии
64. Проблемы при использовании final в PHP
Реалии PHP: исторически сложившаяся “свобода” (не обязательно есть
интерфейсы, не всегда пишутся юнит-тесты)
66. Проблемы при использовании final в PHP
Tests
$pilotMock = $this->createMock(Pilot::class);
$plane = new Plane($pilotMock);
67. Проблемы при использовании final в PHP
Tests
$pilotMock = $this->createMock(Pilot::class);
$plane = new Plane($pilotMock);
final class Pilot {...}
68. Проблемы при использовании final в PHP
Tests
$pilotMock = $this->createMock(Pilot::class);
$plane = new Plane($pilotMock);
final class Pilot {...}
69. Проблемы при использовании final в PHP
Tests
$plane = new Plane(new Pilot(...));
final class Pilot {...}
70. Проблемы при использовании final в PHP
Tests
$plane = new Plane(new Pilot(...));
final class Pilot {...}
Нельзя сделать
mock!
71. Проблемы при использовании final в PHP
Tests
$plane = new Plane(new Pilot(...));
final class Pilot {...}
Нельзя сделать
mock!
Бетон
72. Проблемы при использовании final в PHP
Tests
$plane = new Plane(new Pilot(...));
final class Pilot {...}
Нельзя сделать
mock!
Бетон
ведет себя как new или static
73. Проблемы при использовании final в PHP
Tests
$plane = new Plane(new Pilot(...));
final class Pilot {...}
Нельзя сделать
mock!
Pilot стал неотделимой частью Plane.
Plane может быть протестирован
только вместе с Pilot.
Бетон
ведет себя как new или static
76. Какой принцип проектирования нарушен, что
привело к такому поведению кода?
Вопрос на засыпку
1. Принцип здравого смысла
2. Принцип инверсии зависимостей
3. Нарушено проектирование на уровне интерфейсов
77. Какой принцип проектирования нарушен, что
привело к такому поведению кода?
Вопрос на засыпку
1. Принцип здравого смысла
2. Принцип инверсии зависимостей
3. Нарушено проектирование на уровне интерфейсов
$plane = new Plane(new Pilot(...));
final class Pilot {...}
78. Проблемы при использовании final в PHP
Tests
$plane = new Plane(new Pilot(...));
final class Pilot {...}
Нельзя сделать
mock!
Pilot стал неотделимой частью Plane.
Plane может быть протестирован
только вместе с Pilot.
Бетон
ведет себя как new или static
DIP
violation
Код должен зависеть от абстракций, а не от конкретных классов
82. Проблемы при использовании final в PHP
Tests
Нет
final class Pilot implements Aviator {...}
$pilotMock = $this->createMock(Aviator::class);
$plane = new Plane($pilotMock);
+ Interface
83. Проблемы при использовании final в PHP
Tests
Нет
final class Pilot implements Aviator {...}
$pilotMock = $this->createMock(Aviator::class);
$plane = new Plane($pilotMock);
DIP
compliant!
+ Interface
85. Пример. Final + no Interface
- Надо протестировать вновь созданный Symfony Listener
86. Пример. Final + no Interface
- Надо протестировать вновь созданный Symfony Listener
Как не надо делать
87. Пример. Final + no Interface
- Надо протестировать вновь созданный Symfony Listener
namespace AppInfrastructureBridgeSymfonyListener;
final class RequestListener
{
public function onKernelResponse(ResponseEvent $event): void {
$this->logResponse($event->getResponse());
}
...
}
Как не надо делать
88. Пример. Final + no Interface
- Надо протестировать вновь созданный Symfony Listener
namespace AppInfrastructureBridgeSymfonyListener;
final class RequestListener
{
public function onKernelResponse(ResponseEvent $event): void {
$this->logResponse($event->getResponse());
}
...
}
Как не надо делать
89. Пример. Final + no Interface
- Надо протестировать вновь созданный Symfony Listener
namespace AppInfrastructureBridgeSymfonyListener;
final class RequestListener
{
public function onKernelResponse(ResponseEvent $event): void {
$this->logResponse($event->getResponse());
}
...
}
namespace SymfonyComponentHttpKernelEvent;
final class ResponseEvent extends KernelEvent
{
public function getResponse(): Response {
...
}
...
}
Как не надо делать
90. Пример. Final + no Interface
- Надо протестировать вновь созданный Symfony Listener
namespace AppInfrastructureBridgeSymfonyListener;
final class RequestListener
{
public function onKernelResponse(ResponseEvent $event): void {
$this->logResponse($event->getResponse());
}
...
}
namespace SymfonyComponentHttpKernelEvent;
final class ResponseEvent extends KernelEvent
{
public function getResponse(): Response {
...
}
...
}
Внутренний метод класса, не имеет
объявления во внешнем интерфейсе.
Как не надо делать
91. Пример. Final + no Interface
- Надо протестировать вновь созданный Symfony Listener
namespace SymfonyComponentHttpKernelEvent;
final class ResponseEvent extends KernelEvent
{
public function getResponse(): Response {
...
}
...
}
namespace AppInfrastructureBridgeSymfonyListener;
final class RequestListener
{
public function onKernelResponse(ResponseEvent $event): void {
$this->logResponse($event->getResponse());
}
...
}
Внутренний метод класса, не имеет
объявления во внешнем интерфейсе.
Невозможно создать мок
Как не надо делать
92. Пример. Final + no Interface
- Надо протестировать вновь созданный Symfony Listener
//test code
$event = new ResponseEvent(
static::getMockForAbstractClass(HttpKernelInterface::class),
static::createMock(Request::class),
0,
$response
);
$this->listener->onKernelResponse($event);
namespace SymfonyComponentHttpKernelEvent;
final class ResponseEvent extends KernelEvent
{
public function getResponse(): Response {
...
}
...
}
namespace AppInfrastructureBridgeSymfonyListener;
final class RequestListener
{
public function onKernelResponse(ResponseEvent $event): void {
$this->logResponse($event->getResponse());
}
...
}
Как не надо делать
93. Пример. Final + no Interface
- Надо протестировать вновь созданный Symfony Listener
//test code
$event = new ResponseEvent(
static::getMockForAbstractClass(HttpKernelInterface::class),
static::createMock(Request::class),
0,
$response
);
$this->listener->onKernelResponse($event);
namespace SymfonyComponentHttpKernelEvent;
final class ResponseEvent extends KernelEvent
{
public function getResponse(): Response {
...
}
...
}
namespace AppInfrastructureBridgeSymfonyListener;
final class RequestListener
{
public function onKernelResponse(ResponseEvent $event): void {
$this->logResponse($event->getResponse());
}
...
}
Надо разобраться во внутренних
механизмах класса вместо
создания мока
Как не надо делать
94. Пример. Final + no Interface
- Надо протестировать вновь созданный Symfony Listener
//test code
$event = new ResponseEvent(
static::getMockForAbstractClass(HttpKernelInterface::class),
static::createMock(Request::class),
0,
$response
);
$this->listener->onKernelResponse($event);
namespace SymfonyComponentHttpKernelEvent;
final class ResponseEvent extends KernelEvent
{
public function getResponse(): Response {
...
}
...
}
namespace AppInfrastructureBridgeSymfonyListener;
final class RequestListener
{
public function onKernelResponse(ResponseEvent $event): void {
$this->logResponse($event->getResponse());
}
...
}
Надо разобраться во внутренних
механизмах класса вместо
создания мока
Как не надо делать
95. Пример. Final + no Interface
- Надо протестировать вновь созданный Symfony Listener
namespace SymfonyComponentHttpKernelEvent;
final class ResponseEvent extends KernelEvent
{
public function getResponse(): Response {
...
}
...
}
namespace AppInfrastructureBridgeSymfonyListener;
final class RequestListener
{
public function onKernelResponse(ResponseEvent $event): void {
$this->logResponse($event->getResponse());
}
...
}
Не реализует никакой интерфейс
Но никогда не будет замокан
Как не надо делать
96. Пример. Final + no Interface
- Надо протестировать вновь созданный Symfony Listener
namespace SymfonyComponentHttpKernelEvent;
final class ResponseEvent extends KernelEvent
{
public function getResponse(): Response {
...
}
...
}
namespace AppInfrastructureBridgeSymfonyListener;
final class RequestListener
{
public function onKernelResponse(ResponseEvent $event): void {
$this->logResponse($event->getResponse());
}
...
}
Не реализует никакой интерфейс
Но никогда не будет замокан
Как не надо делать
97. Пример. Final + no Interface
- Надо протестировать вновь созданный Symfony Listener
namespace SymfonyComponentHttpKernelEvent;
final class ResponseEvent extends KernelEvent
{
public function getResponse(): Response {
...
}
...
}
namespace AppInfrastructureBridgeSymfonyListener;
final class RequestListener
{
public function onKernelResponse(ResponseEvent $event): void {
$this->logResponse($event->getResponse());
}
...
}
Не реализует никакой интерфейс
Но никогда не будет замокан
Является библиотечным классом
Как не надо делать
98. Пример. Final + no Interface
- Надо протестировать вновь созданный Symfony Listener
namespace SymfonyComponentHttpKernelEvent;
final class ResponseEvent extends KernelEvent
{
public function getResponse(): Response {
...
}
...
}
namespace AppInfrastructureBridgeSymfonyListener;
final class RequestListener
{
public function onKernelResponse(ResponseEvent $event): void {
$this->logResponse($event->getResponse());
}
...
}
Не реализует никакой интерфейс
Но никогда не будет замокан
Является библиотечным классом
Публичный метод не обьявлен во
внешнем интерфейсе
Как не надо делать
99. Пример. Final + no Interface
- Надо протестировать вновь созданный Symfony Listener
namespace SymfonyComponentHttpKernelEvent;
final class ResponseEvent extends KernelEvent
{
public function getResponse(): Response {
...
}
...
}
namespace AppInfrastructureBridgeSymfonyListener;
final class RequestListener
{
public function onKernelResponse(ResponseEvent $event): void {
$this->logResponse($event->getResponse());
}
...
}
Не реализует никакой интерфейс
Но никогда не будет замокан
Является библиотечным классом
Публичный метод не обьявлен во
внешнем интерфейсе
Должен быть замокан
Как не надо делать
100. Пример. Final + no Interface
- Надо протестировать вновь созданный Symfony Listener
namespace SymfonyComponentHttpKernelEvent;
final class ResponseEvent extends KernelEvent
{
public function getResponse(): Response {
...
}
...
}
namespace AppInfrastructureBridgeSymfonyListener;
final class RequestListener
{
public function onKernelResponse(ResponseEvent $event): void {
$this->logResponse($event->getResponse());
}
...
}
Не реализует никакой интерфейс
Но никогда не будет замокан
Является библиотечным классом
Публичный метод не обьявлен во
внешнем интерфейсе
Должен быть замокан
Как не надо делать
101. Пример. Final + no Interface
- Надо протестировать вновь созданный Symfony Listener
namespace SymfonyComponentHttpKernelEvent;
final class ResponseEvent extends KernelEvent
{
public function getResponse(): Response {
...
}
...
}
namespace AppInfrastructureBridgeSymfonyListener;
final class RequestListener
{
public function onKernelResponse(ResponseEvent $event): void {
$this->logResponse($event->getResponse());
}
...
}
Не реализует никакой интерфейс
Но никогда не будет замокан
Нет понятной причины для
использования final
Является библиотечным классом
Публичный метод не обьявлен во
внешнем интерфейсе
Должен быть замокан
?
Как не надо делать
105. IoC + LSP + final
AbstractAircraft
Plane
Helicopter
AirBalloon
106. IoC + LSP + final
AbstractAircraft
Plane
Helicopter
AirBalloon
abstract class AbstractAircraft
{
public function aviate()
{
$this->prepareToFly();
$this->fly();
$this->reportOk();
}
}
107. IoC + LSP + final
abstract class AbstractAircraft
{
public function aviate()
{
$this->prepareToFly();
$this->fly();
$this->reportOk();
}
abstract protected function prepareToFly();
abstract protected function fly();
abstract protected function reportOk();
}
AbstractAircraft
Plane
Helicopter
AirBalloon
108. IoC + LSP + final
abstract class AbstractAircraft
{
public function aviate()
{
$this->prepareToFly();
$this->fly();
$this->reportOk();
}
abstract protected function prepareToFly();
abstract protected function fly();
abstract protected function reportOk();
}
AbstractAircraft
Plane
Helicopter
AirBalloon
Hollywood principle
(IoC)
109. IoC + LSP + final
abstract class AbstractAircraft
{
public function aviate()
{
$this->prepareToFly();
$this->fly();
$this->reportOk();
}
abstract protected function prepareToFly();
abstract protected function fly();
abstract protected function reportOk();
}
AbstractAircraft
Plane
Helicopter
AirBalloon
Hollywood principle
(IoC)
Наследники могут переопределять
поведение базового класса
110. IoC + LSP + final
abstract class AbstractAircraft
{
final public function aviate()
{
$this->prepareToFly();
$this->fly();
$this->reportOk();
}
abstract protected function prepareToFly();
abstract protected function fly();
abstract protected function reportOk();
}
AbstractAircraft
Plane
Helicopter
AirBalloon
Hollywood principle
(IoC)
Наследники могут переопределять
поведение базового класса
111. IoC + LSP + final
abstract class AbstractAircraft
{
final public function aviate()
{
$this->prepareToFly();
$this->fly();
$this->reportOk();
}
abstract protected function prepareToFly();
abstract protected function fly();
abstract protected function reportOk();
}
AbstractAircraft
Plane
Helicopter
AirBalloon
Hollywood principle
(IoC)
LSP compliant
112. Что здесь не так?
abstract class AbstractAircraft
{
final public function aviate()
{
$this->prepareToFly();
$this->fly();
$this->reportOk();
}
abstract protected function prepareToFly();
abstract protected function fly();
abstract protected function reportOk();
}
AbstractAircraft
Plane
Helicopter
AirBalloon
Hollywood principle
(IoC)
LSP compliant
113. Нужен интерфейс!
abstract class AbstractAircraft
{
final public function aviate()
{
$this->prepareToFly();
$this->fly();
$this->reportOk();
}
abstract protected function prepareToFly();
abstract protected function fly();
abstract protected function reportOk();
}
AbstractAircraft
Plane
Helicopter
AirBalloon
Hollywood principle
(IoC)
LSP compliant
Бетон!
Не мокается!
114. Так нужен ли final в PHP или нет?
1. Скорее нужен, чем не нужен
2. Скорее не нужен, чем нужен
3. Очень нужен для IoC + LSP + final
115. Так нужен ли final в PHP или нет?
1. Скорее нужен, чем не нужен
2. Скорее не нужен, чем нужен
3. Очень нужен для IoC + LSP + final
Зависит от
архитектурного
стиля
123. Мои статьи:
Уровни абстракций
Принцип инверсии зависимостей
Принцип подстановки Барбары Лисков
Голливудский принцип (IoC)
Не мои статьи:
Гонка данных
Книжка:
Паттерны проектирования O’reilly
Что почитать?
124. Мои контакты
О серьезном писать сюда: https://www.linkedin.com/in/natalynyshta/
(или сюда amriwman@gmail.com)
О несерьезном сюда: https://www.facebook.com/amriwman/