Ключевое слово: class
Документация: https://www.php.net/manual/ru/language.oop5.basic.php
Описание:
С помощью классов мы описываем модели, разделяем сложную логику на маленькие кусочки. Чем проще и понятней написан класс, тем удобнее будет с ним работать. И наоборот, чем больше у класса свойств и методов, тем бесполезней он для программиста (см. золотой молоток).
Пример использования:
class MyClass
{
// Свойства
public $var1, $var2, $var3;
// Методы
public function calc($arg1, $arg2) {
// Логика поведения
return $this->var1 * $arg1 + $arg2;
}
}
$object = new MyClass(); // Из класса создаются объекты
$object->var1 = 10;
echo $object->calc(20, 30); // 230
Ключевые слова: namespace
Документация: https://www.php.net/manual/ru/language.namespaces.rationale.php
Описание:
Пространства имён нужны для удобства управления большим количеством классов. С помощью них мы работаем с классами как с файлами и папками. Ещё они помогают разрешить конфликты имён: если два класса имеют одно название, просто задайте им разные namespace.
Пример использования:
Файл: classes/MyShop/Order.php
<?php
namespace MyShop;
// Класс заказа
class Order {
// Возвращает строчки заказа
function lines() {
return [
new Order\Line(), // Строчка 1
new Order\Line(), // Строчка 2
];
}
}
?>
Файл: classes/MyShop/Order/Line.php
<?php
namespace MyShop\Order;
// Строчка заказа
class Line {
// ...
}
?>
Файл: index.php
<?php
$order = new MyShop\Order();
var_dump($order->lines());
Ключевое слово: new
Документация: https://www.php.net/manual/ru/language.oop5.basic.php#language.oop5.basic.new
Описание:
У объектов мы вызываем методы и задаём свойства. Каждый объект является экземпляром какого-то класса. Объекты всегда передаются по ссылке (это означает, что изменения объекта будут доступны везде).
Пример использования:
$obj1 = new MyClass($arg1, $arg2); // Создание объекта из класса MyClass с параметрами
$obj2 = new OtherClass; // Создание объекта из класса OtherClass без параметров
Ключевое слово: __construct
Документация: https://www.php.net/manual/ru/language.oop5.decon.php#language.oop5.decon.constructor
Описание:
Функция-конструктор однократно вызывается для каждого объекта при создании. В ней мы задаём начальное состояние нового объекта. Например, можно получить данные через аргументы и записать их в контекст объекта. Также можно создавать зависимые объекты, которые нужны для работы. Важно помнить, что функция-конструктор не должна возвращать значение.
Пример использования:
class MyClass {
private $arg1, $arg2;
// Объявляем функцию-конструктор
function __construct($arg1, $arg2 = 123) {
$this->arg1 = $arg1;
$this->arg2 = $arg2;
}
function calc() {
return $this->arg1 + $this->arg2;
}
}
$sum = new MyClass(10, 20);
echo $sum->calc(); // 30
Ключевое слово: __destruct
Документация: https://www.php.net/manual/ru/language.oop5.decon.php#language.oop5.decon.destructor
Описание:
Функция-деструктор вызывается однократно для каждого объекта при уничтожении. Мы используем её для очистки ресурсов объекта. Например, сделали класс для работы с изображениями и нужно, чтобы ресурсы очищались сразу, как только умрёт объект. Ещё деструкторы удобно использовать при отладке, чтобы понимать, как долго живёт объект.
Пример использования:
class MyClass {
// Объявляем деструктор
function __destruct() {
printf("Объект %s(#%s) уничтожен\n",
get_class($this),
spl_object_id($this)
);
}
}
$obj1 = new MyClass();
$obj2 = new MyClass();
unset($obj2); // Объект MyClass(#2) уничтожен
unset($obj1); // Объект MyClass(#1) уничтожен
Ключевое слово: clone
Документация: https://www.php.net/manual/ru/language.oop5.cloning.php
Описание:
Мы используем клонирование, чтобы создавать дубли объектов. Это единственный способ создать копию, поскольку объекты всегда передаются по ссылке.
Пример использования:
// Создаём объект
$a = new stdClass();
$a->foo = 'bar';
// Простое присваивание передаёт ссылку на начальный объект
$b = $a;
$b->foo = '123';
// Мы изменили $b, но данные поменялись и в $a
echo $a->foo, PHP_EOL; // 123
echo '---', PHP_EOL;
// Клонируем объект
$c = clone $b;
$c->foo = 'bee';
// Мы изменили $c, данные поменялись только в $c
echo $a->foo, PHP_EOL; // 123
echo $b->foo, PHP_EOL; // 123
echo $c->foo, PHP_EOL; // bee
Ключевое слово: extends
Документация: https://www.php.net/manual/ru/language.oop5.inheritance.php
Описание:
В базовый класс мы выносим общие свойства и методы, которые могут использовать потомки. Таким образом выстраивается иерархия классов. Нужно помнить, что в PHP базовый класс может быть только один.
Пример использования:
// Базовый класс
class Decorator {
private $text;
function __construct($text) {
$this->text = $text;
}
// "Магическая функция", которая вызывается для преобразования объекта в строк
function __toString() {
return $this->text;
}
}
// Класс-потомок
class Bold extends Decorator {
function __toString() {
return "<strong>" . parent::__toString() . "</strong>";
}
}
// Класс-потомок
class Italic extends Decorator {
function __toString() {
return "<i>" . parent::__toString() . "</i>";
}
}
echo new Bold("Жирный"), PHP_EOL; // <strong>Жирный</strong>
echo new Italic("Наклонный"), PHP_EOL; // <i>Наклонный</i>
Ключевые слова: interface, implements
Документация: https://www.php.net/manual/ru/language.oop5.interfaces.php
Описание:
Мы используем интерфейсы, когда хотим указать, какие функции нам нужны. Это удобно, когда классов ещё нет или они только проектируются. Также с помощью интерфейсов можно отвязаться от конкретных классов, если нужны только некоторые функции.
Мы можем написать интерфейсы заранее, посмотреть, как они будут себя вести (например, через Unit-тест), а только потом писать основной код. Это уберегает от глупых ошибок.
Нужно помнить, что интерфейс может содержать в себе только константы и функции без реализации.
Пример использования:
// Функции для работы со свойствами "Человека"
interface Person {
function firstName();
function lastName();
}
// Функции для работы со свойствами "Водителя"
interface Driver extends Person {
function license();
}
// Функции для преобразования объекта в строку
interface Stringify {
function __toString();
}
// Функция ожидает на вход любой объект, который реализует интерфейс "Человек"
function personName(Person $person) {
return $person->lastName() . ' ' . $person->firstName();
}
// Функция ожидает на вход любой объект, который реализует интерфейс "Водитель"
function driverLicense(Driver $driver) {
return $driver->license();
}
// Класс может реализовывать любое количество интерфейсов
class MyClass implements Driver, Stringify {
function firstName() {
return "Иван";
}
function lastName() {
return "Петров";
}
function license() {
return "AA123";
}
function __toString() {
return spring("Driver: %s, License: %s",
personName($this),
driverLicense($this)
);
}
}
echo new MyClass; // Driver: Петров Иван, License: AA123
Ключевое слово: abstract
Документация: https://www.php.net/manual/ru/language.oop5.abstract.php
Описание:
С помощью абстрактных классов и методов мы перекладываем обязанность "реализовать логику" на кого-то другого. А среда исполнения будет пристально бдить, чтобы все абстрактные методы были реализованы. Нужно помнить, что абстрактные классы всегда предполагают, что их кто-то будет наследовать.
Пример использования:
// Базовый класс фигур
abstract class Shape {
abstract function name(); // Делегируем функцию потомкам
abstract function square(); // Делегируем функцию потомкам
function __toString() {
return sprintf("Фигура: %s, Площадь: %.3f",
$this->name(),
$this->square()
);
}
}
class Rectangle extends Shape {
private $width, $height;
function __construct($width, $height) {
$this->width = $width;
$this->height = $height;
}
function name() {
return "Прямоугольник";
}
function square() {
return $this->width * $this->height;
}
}
class Circle extends Shape {
private $radius;
function __construct($radius) {
$this->radius = $radius;
}
function name() {
return "Круг";
}
function square() {
return pi() * $this->radius * $this->radius;
}
}
echo new Rectangle(10, 20), PHP_EOL; // Фигура: Прямоугольник, Площадь: 200.000
echo new Circle(20), PHP_EOL; // Фигура: Круг, Площадь: 1256.637
Ключевое слово: -
Документация: https://www.php.net/manual/ru/language.oop5.overloading.php
Описание:
Мы используем перегрузку функций, когда нужно изменить логику класса без изменения самого класса. При этом можно обращаться и к родительским функциям, используя конструкцию parent::
.
Пример использования:
class A {
function name() {
return "Вася";
}
function greeting() {
echo "Здравствуй, ", $this->name();
}
}
class B extends A {
function name() {
return "Петя";
}
}
$obj = new B();
$obj->greeting(); // Здравствуй, Петя
Ключевое слово: final
Документация: https://www.php.net/manual/ru/language.oop5.final.php
Описание:
Мы используем финализацию, чтобы запретить программисту использовать наш класс неправильно. Например, когда пишем библиотеку, которую будет использовать кто-то другой.
Пример использования:
class A {
final function foo() {
}
}
class B extends A {
function foo() { // Fatal error: Cannot override final method A::foo()
}
}
final class C {
}
class D extends C { // Fatal error: Class D may not inherit from final class (C)
}
Ключевые слова: public, protected, private
Документация: https://www.php.net/manual/ru/language.oop5.visibility.php
Описание:
Мы используем область видимости, чтобы скрыть внутреннюю реализацию класса. Нам неважно, как устроен класс изнутри, нам важно, какие у него публичные методы.
Существует три типа видимости:
Старайтесь не использовать публичные свойства, в PHP они плохо контролируются, используйте публичные методы.
Пример использования:
class A {
final private $firstName = 'Вася';
protected $middleName = 'Васильиевич';
public $lastName = 'Васильев';
function name() {
return join(' ', [
$this->firstName,
$this->middleName,
$this->lastName
]);
}
}
class B extends A {
private $firstName = 'Петя';
protected $middleName = 'Петрович';
public $lastName = 'Петров';
}
$obj = new B();
// Вызов метода
echo $obj->name(); // Вася Петрович Петров
// Доступ к свойствам
$obj->firstName = ''; // Error: Cannot access private property
$obj->middleName = ''; // Error: Cannot access protected property
$obj->lastName = ''; // Без ошибок
Ключевые слова: static, self
Документация: https://www.php.net/manual/ru/language.oop5.static.php
Описание:
Мы используем статичные переменные и методы, если хотим сделать их глобальными, а не привязанными к отдельным объектам. В статичных методах нельзя использовать $this.
Пример использования:
class A {
static public $myVar = 123;
static function greeting() {
echo "Привет, ", self::$myVar, "!", PHP_EOL;
}
}
A::$myVar = "мир";
A::greeting(); // Привет, мир!
$obj = new A();
A::$myVar = "Вася";
$obj->greeting(); // Привет, Вася!
Ключевое слово:: static
Документация: https://www.php.net/manual/ru/language.oop5.late-static-bindings.php
Описание:
Мы используем позднее связывание, чтобы перегружать статичные свойства и методы, поскольку self всегда ссылается только на текущий класс.
Пример использования:
class A {
static public $name = "Вася";
static function test() {
echo 'self::$name ', self::$name, PHP_EOL;
echo 'static::$name ', static::$name, PHP_EOL;
}
}
class B extends A {
static public $name = "Петя";
}
B::test(); // self::$name Вася
// static::$name Петя
Ключевое слово: pattern
Зачем нужно: типовые решения типовых проблем.
Документация: https://ru.wikipedia.org/wiki/Шаблон_проектирования
Описание:
Мы используем шаблоны проектирования, чтобы не изобретать "велосипед". Большинство задач, с которыми программисты сталкиваются каждый день, уже были решены много раз до этого. Наиболее правильные решения были описаны на разных языках программирования и названы "шаблонами проектирования". Их нужно знать, чтобы, как минимум, понимать, о чём идёт речь в разговорах с программистами.
Использование:
<Ведущий разработчик>: А вот здесь надо использовать декомпозицию и реджистри.
<Программист>: (многозначительно кивает)
<Ведущий разработчик>: Сюда хорошо встанет обсервер.
<Программист>: (делает вид, что понимает)
<Ведущий разработчик>: Вопросы есть?
<Программист>: Нет, тут же всё просто!
<Ведущий разработчик>: (уходит в закат)
<Программист>: (с двойным усердием продолжает писать херню)
Ключевое слово: solid
Зачем нужно: принципы разработки качественных приложений.
Документация: https://ru.wikipedia.org/wiki/SOLID_(объектно-ориентированное_программирование)
Описание:
Мы используем слово SOLID, когда хотим показать свою важность и крутость. Всё дело в том, что на практике мало кто разбирается, что это такое и как оно должно работать. Но, если программист говорит, что не знает SOLID, то в него принято кидать какашки.
В SOLID есть 5 базовых принципов:
Использование:
<Ведущий разработчик>: Почему ты не применил тут декомпозицию и реджистри?
<Программист>: Потому что в данном случае это нарушило бы принцип
открытости-закрытости, а реджистри нарушает инверсию
зависимостей.
<Ведущий разработчик>: А обсервер-то почему не сделал?
<Программист>: Это нарушило бы принцип единой ответственности.
Должна быть только одна причина для изменения класса.
<Ведущий разработчик>: (впал в задумчивость)
<Программист>: (делает умный вид)
<Ведущий разработчик>: Ты прав! Мы не должны нарушать принципы SOLID.
<Программист>: Именно, ведь мы серьёзные разработчики.
<Ведущий разработчик>: (довольный уходит в закат)
<Программист>: (лениво дописывает херню)