oop-php

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

Весь код содержится в классах. То, что в функциональном (процедурном) программировании называлось переменной — в ООП называется свойство. Функции в ООП называются методами. Т.е. внутри класса описываются свойства и методы класса. Созданные на основе класса объекты называются экземплярами класса или просто объекты. Также теперь появляются метод объекта и свойство объекта.

Обращение из метода к свойствам только через служебное слово $this: $this->name; (обратите внимание на отсутствие знака доллара перед name)

Обращение внутри метода к другому методу тоже через $this: $this->foo();

Конструктор — это метод, который автоматически вызывается при создании нового объекта: public function __construct(){} (знак двойного подчеркивания __ относится к магическим методам). При инициализации объекта через служебную конструкцию new, PHP ищет метод __construct  и если он есть, то вызывается:

Деструктор — метод, который автоматически вызывается при удалении объекта: public function __destruct(){}. Все созданные объекты удаляются в конце выполнения кода, даже без unset. деструктор не принимает аргументов. Очередность удаления объектов не определена. Поэтому не стоит из деструктора обращаться к другим объектам, т.к. они уже могут быть удалены.

Как правило конструкторы и деструкторы описываются в начале класса.

В PHP4 конструктором был метод с именем класса, это работает и в PHP5, если нет __construct(){}

$a = $b (копирование)

$a = &$b (‘a’ ссылка на ‘b’)

В PHP4 это работало для всех типов. В PHP5 (PHP7) это работает для всех типов, кроме объектов:

$a (object) = $b (object) — ‘a’ ссылка на ‘b’

Т.е. $a = new Animal(); ($a — это ссылка на объект)

Копирование (клонирование) объекта: $a = clone $b;

Конструктор не вызывается при клонировании. __clone(){} — магический метод, вызываемый при клонировании. Он НЕ принимает аргументов и к нему нельзя обратиться как к методу.

Наследование в ООП

Класс это телевизор. А у нас пульт от телевизора для управления. Если что-то не хватает в нужном классе — наследуем его и добавляем свой функционал. После этого доступны свойства и методы обоих классов. Множественное наследование НЕ поддерживается, наследовать можно только 1 класс. Конструктор тоже наследуется!

class Toyota extends Car { … }

Перегрузка метода — если в классе-наследнике описан метод с тем же именем, что и в родительском.

Обращение к родительскому методу из наследованного:

parent::method();

Т.е мы можем наш метод назвать также, как в родительском классе, вызвав внутри метода родительский метод:

Перегружаемый метод принимает столько же параметров, как и в родительском классе!

Модификаторы доступа в ООП

  • public — позволяет иметь доступ к свойствам и методам из любого места (глобальная область)
  • protected — доступ к родительскому и наследуемому классу (область класса наследника)
  • private — доступ только из класса, в котором объявлен сам элемент (область самого класса)

Иногда свойства для внутреннего использования передваряют знаком подчеркивания: $_name; (protected или private)

Метод по умолчанию — public (если не указан модификатор). У свойств значения модификатора по умолчанию НЕТ.

Обработка исключений в ООП

Применение: обработка некритических ошибок.

Exception — встроенный класс, которых много в PHP. Наблюдается все большая тенденция перехода в классы.

Если попали в throw, то код ниже НЕ выполняется и осуществляется переход к блоку catch. Не выполняется код в блоке try, после throw.

Блок try-catch используется как в процедурном, так и в ООП программировании. Он используется для отлова ошибок — большой блок try с множеством throw и все отлавливаются в одном месте — блоке catch.

Exception можно наследовать, желательно при этом перезагрузить конструктор:

Блоков catch может быть несколько — для каждого класса наследника Exception.

foreach может проходить по свойствам объекта:

Константы в ООП

const NAME = 2;

В новых версиях PHP таким образом можно создавать константы и вне класса. Подробнее здесь. Это именно константы класса, они не принадлежат ни одному объекту, они общие на все объекты, поэтому использование внутри метода:

self — это сам класс!

Обращение вне класса (можно вызывать из глобальной области видимости без инициализации экземпляра класса):

echo OurClass::NAME;

Абстрактные классы

abstract class DB { … }

Нельзя создавать экземпляр от абстрактного класса, его можно только наследовать. Это как бы набросок.

Абстрактный метод:

abstract function test();

это метод без реализации, у него нет фигурных скобок.

Абстрактный класс может и не содержать абстрактных методов. Унаследованный класс обязан описать ВСЕ абстрактные методы. Как минимум перезагрузить методы. Используется в больших проектах для удобства работы в команде.

Интерфейсы

Это абстрактный класс, который содержит только абстрактные методы. Тоже типа набросок, но еще более грубого уровня, чем сам абстрактный класс. Поскольку все методы абстрактные, то слово abstract писать НЕ надо:

Интерфейс — это контракт, говорящий, что будет то, то и то… Его можно только наследовать. Наследуется с помощью ключевого слова implements:

Можно наследовать сразу несколько интерфейсов через запятую. Класс может быть унаследован от другого класса + сколько угодно интерфейсов. Один интерфейс — много реализаций. *Недостаток: у унаследованнх интерфейсов не может быть одноименных методов!

Делаем из объекта ассоциативный массив из свойств и значений; внутри метода: return (array) $this; — при приведении объекта к типу массив — получится ассоциативный массив.

Финальные методы

НЕ могут быть перегружены. Обычно используют, когда метод еще не доделан и планируется внести изменения в будущем. Т.е. чтобы люди пока не подсаживались на этот метод.

Все методы класса Exception являются финальными, т.е. планируются изменения в будущем.

final function test() { … }

Класс тоже может быть финальным (его нельзя наследовать, такой вариант редко используется):

final class User { … }

Статические свойства и методы

public static $test = 0;

Статическое свойство. Одно на всех, статическое свойство класса, подобно константе. Обращение к статическому свойству класса изнутри класса только через self (не забывать знак $ перед именем свойства!):

Обращение из глобальной области:

echo ClassName::$test;

Статический метод также один на всех, никому не принадлежит. К ним можно обращаться НЕ объявляя экземпляр класса.

public static function foo() { … }

Динамические статические вызовы

При создании класса, создавайте хотя пустые методы __construct и __clone. При изменении конструктора также возможно понадобится внести изменения и в __clone.

instanceOf

Отслеживает всю цепочку наследований, абстракций, интерфейсов и т.д. Аналогично функции is_a($obj, ‘class’);

__autoload

Магическая функция, запускается если создается новый объект, пример

Таким образом подключаем только используемые классы.

Геттеры и сеттеры

Такие себе костыли от джавистов __get и __set. Запрашиваются при попытке присвоения значения к свойству, не объявленному в классе в классическом виде. Это называется доступ к невидимым свойствам. Т.е. прежде чем выдать ошибку при обращении к свойству, которого нет — проверяются геттеры и сеттеры. Сеттер принимает имя свойства и его значение. Метод и свойство, которых может не быть или они приватны.

function __set($n, $value) { … }

Если следует обращение к методу, которого нет, то прежде чем вызвать ошибку — проверяется, не описан ли магический метод __call. Он принимает имя метода и массив аргументов:

function __call($n, $args) { … }

Магический метод __toString

Вызывается, если есть попытка вывести объект, как строку, иначе ошибка

Магический метод __invoke

public function __invoke($var) { … }

Вызывается при попытке обращения к объекту, как к функции:

Значение 5 передается в метод __invoke, если __invoke нет — будет ошибка. Смысла особого в этом методе нет, просто фича. Объект как функция. Параметров может быть сколько угодно.

Traits

Самый обычный класс, не наследуется, а по сути инклюдятся в другой класс. Т.е. решают проблему множественного наследования.

Трейты могут и сами наследовать другие трейты (через use). Таким образом обеспечивается модальность.