§6. Классы и объекты
6.1. Создание классов и объектов.
Понятия объекта и класса являются ключевыми в объектно-ориентированных языках программирования, к которым относится также и язык PHP. Объекты в нем представляют собой один из типов данных и становятся доступными после описания соответствующего класса.
Класс – это шаблон кода, который используется для создания объектов.
Каждое определение класса начинается с ключевого слова class, затем записывается имя класса и при помощи пары фигурных скобок формируется тело класса, в котором определяются свойства и методы этого класса (см. пример 6.1).
<?php class empty_class{ //Объявили пустой класс без свойств и методов } $empty_1=new empty_class(); //Создали экземпляр класса, т.е. объект $empty_2=new empty_class(); //Создали еще один экземпляр класса, т.е. объект ?>
Пример 6.1. Определение класса и создание объектов
Имена классов являются регистронезависимыми и должны начинаться с буквы или символа подчеркивания, за которым может следовать любое количество букв, цифр или символов подчеркивания. При этом имя класса не должно входить в список зарезервированных слов PHP.
После того, как класс будет создан, можно создавать его отдельные экземпляры, т.е. объекты, и сохранять их в переменных. Для этого используется ключевое слово new, после которого указывается имя класса, экземпляром которого будет являться создаваемый объект. Так в примере выше было создано два объекта типа empty_class. И хотя оба они пусты – это все равно два полноценных независимых объекта, принадлежащих к одному и тому же типу, т.к. они являются экземплярами одного и того же класса.
При сохранении объектов в переменных происходит присвоение не самого объекта, а специального идентификатора (ссылки), по которому этот объект можно будет найти при обращении к нему позднее. Соответственно, если мы присвоим один и тот же объект двум разным переменным, то они будут хранить один и тот же идентификатор объекта, а при изменении значения любой из них, будет изменено значение и другой. Внешне такой процесс воспринимается, как присвоение объектов переменным по ссылке (в отличие от переменных, которые по умолчанию присваиваются по значению) с той лишь разницей, что присваиваются не сами объекты, а их идентификаторы.
Объекты очень важны для объектно-ориентированного программирования, поскольку позволяют скрывать от внешнего мира детали своего внутреннего устройства, которое может быть изменено без необходимости внесения изменений в использующий их код. При этом работа над каждым отдельным модулем в виде объекта может вестись отдельно, а по завершении разработки готовые модули могут быть соединены воедино в виде масштабного комплексного приложения. Данный процесс можно наглядно представить на примере из жизни, когда отдельные модули МКС собираются независимо друг от друга разными странами, а затем на орбите собираются в одну монолитную космическую станцию посредством готовых интерфейсов, обеспечивающих взаимодействие готовых модулей между собой.
6.2. Определение констант, свойств и методов класса.
В процессе создания класса в его теле могут создаваться константы, переменные или функции. Переменные, создаваемые внутри класса, принято называть свойствами, а функции методами этого класса (см. пример 6.2).
<?php class my_class{ //Объявили класс const my_const='Строковая константа'; //Создаем константу public $my_name; //Объявили, но неинициализировали свойство класса function set_name($text){ //Создаем метод класса, который устанавливает //значение его свойства my_name $this->my_name=$text; //Ключевое слово $this ссылается на сам объект } } $person=new my_class(); //Создали экземпляр класса, т.е. объект $person->set_name('Иван'); //Установили значение его свойства my_name echo $person->my_name.'<br>'; //Выведет строку 'Иван' echo $person::my_const; //Выведет 'Строковая константа' ?>
Пример 6.2. Определение свойств и методов класса
Константы внутри классов создаются при помощи служебного слова const, после которого указывается имя константы и присваивается ее значение. Опять же, перед именем константы знак доллара '$' не ставится, а значением константы может быть только неизменяемое (скалярное) выражение, например, число, массив или строка, определенная при помощи синтаксиса nowdoc, но не переменная, результат вызова функции или что-то подобное.
Перед именем свойств и методов обычно указывается одно из следующих ключевых слов (модификаторов), определяющих уровень доступа к нему:
- public – доступ к свойствам и методам класса разрешен отовсюду;
- protected – доступ к свойствам и методам класса разрешен из наследуемых и родительских классов;
- private – доступ к свойствам и методам класса разрешен только внутри самого класса.
Методы, в которых уровень доступа при помощи перечисленных модификаторов не указан, определяются как public.
В случае инициализации свойства класса во время его объявления разрешается применять только константные выражения, т.е они должны быть окончательно вычислены еще во время компиляции, а не зависеть от данных программы во время ее выполнения. При этом инициализировать свойства внутри класса не обязательно, т.к. если значение не указать, свойству по умолчанию будет присвоено значение NULL.
После того, как какой-либо объект класса будет создан, свойства и методы класса становятся доступны для использования через указание имени объекта, объектного оператора '->', а также имени свойства или метода. Однако следует помнить, что при обращении к свойству объекта знак доллара '$' перед ним нужно опускать, а при вызове метода объекта нужно указывать круглые скобки. Доступ к константам, после создания экземпляра класса, отличается от доступа к свойствам или методам и осуществляется при помощи оператора двойного двоеточия '::' (см. пример 6.2).
Для обращения изнутри текущего метода к другим свойствам или методам внутри этого же класса используется специальная псевдопеременная $this, которая представляет собой ссылку на текущий объект, в контексте которого вызывается данный метод.
Псевдопеременная $this всегда указывает на текущий объект, поэтому присвоение ей какого-либо значения недопустимо.
По умолчанию методы могут принимать аргументы любого типа. Однако иногда возникает необходимость сделать так, чтобы метод мог принимать в качестве аргументов, например, только массивы или же экземпляры какого-то определенного класса. В таких случаях следует просто указать разрешенный тип данных перед именем аргумента (см. пример 6.3).
<?php class my_class{ function test(other_class $arg){ //Первый аргумент метода должен быть //экземпляром класса other_class echo $arg->my_var; } function test_array(array $arg_1,$arg_2){ //Первый аргумент должен быть echo $arg_1[0].' '.$arg_2; //массивом, второй любой доступный } } class other_class{ //Создаем еще один класс public $my_var = 'Привет!'.'<br>'; //и определяем в нем свойство } $obj=new my_class(); //Создаем экземпляр класса my_class $other_obj=new other_class(); //Создаем экземпляр класса other_class $obj->test($other_obj); //Выведет строку 'Привет' //$obj->test(7); //Выведет ошибку, т.к. передан недопустимый //тип данных (число вместо экземпляра класса) $arr=['a','b','c']; //Определяем массив $obj->test_array($arr,5); //Выведет строку 'a 5' //$obj->test_array(5,$arr);//Выведет ошибку, первый аргумент должен быть массивом ?>
Пример 6.3. Осуществление контроля типа аргументов
Список разрешенных типов, а также особенности применения контроля типов можно посмотреть в разделе, посвященному функциям (перейти).
Отметим, что в PHP имеется возможность обращаться к свойствам и методам класса без объявления его экземпляров, т.е. без создания объектов соответствующего типа. Для этого они должны быть объявлены статическими при помощи ключевого слова static (см. пример 6.4).
<?php class my_class{ //Объявили класс static public $my_text='Текст '; //Объявили статическое свойство класса static function get_func(){ //Создаем статический метод класса echo 'Функция'.'<br>'; //Выведет строку 'Функция' //$this->my_name='text'; - $this недопустимо в статических методах } } echo my_class::$my_text.'<br>'; //Выведет строку 'Текст' без создания объекта $a='my_class'; //Присвоили имя класса переменной echo $a::$my_text.'<br>'; //Также выведет строку 'Текст' my_class::get_func(); //Выведет строку 'Функция' $a::get_func(); //Также выведет строку 'Функция' $person=new my_class(); //Создали экземпляр класса, т.е. объект //$person->get_func(); //Выведет строку 'Функция', т.к. статические //методы остаются доступны и в объектах //echo $person->my_text; //Выведет ошибку!!! Свойства, объявленные //статическими, становятся недоступными в объектах ?>
Пример 6.4. Использование ключевого слова static
Доступ к статическим свойствам и методам класса, как и в случае с константами класса, осуществляется при помощи оператора двойного двоеточия '::'. Однако при доступе к статическому свойству нужно указывать перед его идентификатором знак доллара, иначе интерпретатор будет пытаться получить доступ не к статическому свойству, а к константе класса. Кроме того, обращение к статическим свойствам при помощи объектного оператора '->' невозможно. Что касается статических методов, то при обращении к ним снаружи объекта должно использоваться только двойное двоеточие '::', внутри же объекта разрешается использовать как двойное двоеточие '::', так и объектный оператор '->', хотя мы будем всегда использовать только двойное двоеточие (см. пример 6.4).
Как и в случае с константами, значением статического свойства может быть только неизменяемое (скалярное) выражение, например, число, массив или строка, определенная при помощи синтаксиса nowdoc, но не переменная, результат вызова функции или что-то подобное. Кроме того, поскольку статические методы могут вызываться без создания экземпляра класса, то псевдопеременная $this не доступна внутри метода, объявленного статическим, даже в случае, когда он вызывается изнутри объекта.
Также отметим, что в PHP разрешается ссылаться на класс посредством переменных (наподобие концепции переменных функций). Соответственно, значение переменной в таком случае не должно являться ключевым словом PHP (см. пример 6.4).
6.3. Наследование в PHP.
Наследование представляет собой еще один хорошо зарекомендовавший себя принцип объектно-ориентированного программирования, который широко используется в объектной модели PHP.
Наследование – это механизм объектно-ориентированного программирования, который используется для описания новых классов на основе уже существующего.
Исходный класс, на основе которого происходит наследование свойств и методов, называют родительским классом, а классы, получающиеся в результате наследования – классами-потомками.
При объявлении класса-потомка после его имени используется ключевое слово extends, а также указывается имя родительского класса, от которого выполняется наследование (см. пример 6.5).
<?php class first_name{ //Объявили родительский класс public $my_first_name; //Объявили, но неинициализировали свойство класса function set_first_name($text){ //Метод устанавливает имя $this->my_first_name=$text; } } $person=new first_name(); //Создаем новый объект $person->set_first_name('Иван'); //Установили значение имени //$person->set_last_name('Кожемяко'); //Вызовет ошибку, т.к. метода не существует!!! /* Расширим наш класс, добавив новое свойство и метод для установки фамилии */ class full_name extends first_name{ //Создаем класс-потомок public $my_last_name; //Добавили новое свойство function set_last_name($text){ //Добавили новый метод, который $this->my_last_name=$text; //устанавливает фамилию } } $person_2=new full_name(); //Создаем новый объект класса-потомка $person_2->set_first_name('Иван'); //Установили значение имени $person_2->set_last_name('Кожемяко'); //Установили значение фамилии echo $person_2->my_first_name.' '.$person_2->my_last_name; //Выведет 'Иван Кожемяко' /* Не забываем набирать код в редакторе. Для временного изолирования ненужного кода, например, в строке 11, можно применять его комментирование */ ?>
Пример 6.5. Создание классов-потомков
Классы-потомки наследуют все доступные свойства и методы своего родительского класса, а также константы. Кроме того, они могут переопределять их (включая константы, но за исключением случаев, когда метод родительского класса объявлен как final), а также добавлять собственные константы, свойства и методы.
Когда в классе-потомке переопределяются методы родительского класса, число и типы их аргументов должны оставаться прежними, иначе будет вызвана ошибка. Это не относится к методам-конструкторам (о них чуть позже), которые могут быть переопределены с другими параметрами.
Наследование нескольких классов в PHP недопустимо, поэтому у каждого класса-потомка может быть не более одного родительского класса, который должен объявляться до момента объявления любого из своих классов-потомков.
Для доступа изнутри метода класса-потомка к собственным или родительским свойствам и методам, а также константам используются соответствующие конструкции self:: и parent:: (см. пример 6.6).
<?php class parent_class{ //Объявили родительский класс public $my_var='value '; //Объявили свойство класса const parent_const='parent_constant '; //Объявили константу класса function my_func(){ //Определяем метод echo $this->my_var; //Выводим значение свойства } } class descendant_class extends parent_class{ //Создаем класс-потомок const self_const='self_constant '; //Объявили константу класса-потомка function my_func(){ //Переопределяем родительский метод parent::my_func(); //Вызываем родительский метод, и дополняем его echo parent::parent_const.'<br>';//выводом константы (тут можно и $this::my_const;) } function self_func(){ //Определяем новый метод класса-потомка self::my_func(); //Вызываем метод текущего класса-потомка, //хотя можно и привычным способом $this->my_func(); echo self::self_const.'<br>';//Выводим константу класса-потомка //Здесь можно использовать и $this::self_const; } } $descendant_obj=new descendant_class(); //Создаем новый объект $descendant_obj->my_func(); //Вызываем метод объекта класса-потомка $descendant_obj->self_func(); //Вызываем метод объекта класса-потомка echo $descendant_obj::self_const.'<br>';//Выводим константу класса-потомка ?>
Пример 6.6. Использование конструкций parent:: и self::
Что касается ключевого слова final, то использование его перед объявлениями методов класса делает их недоступными для переопределения в классах-потомках. Если же ключевое слово final присутствует во время определения самого класса, то весь класс становится недоступным для наследования (см. пример 6.7).
<?php class parent_class{ //Объявили родительский класс public $my_var='value '; //Объявили свойство класса final function my_func(){ //Определяем и финализируем метод echo $this->my_var; //Выводим значение свойства } } class descendant_class extends parent_class{ //Создаем класс-потомок function my_func(){ //Переопределение вызовет ошибку!!! parent::my_func(); echo 'Нельзя переопределять финализированный метод'; } } ?>
Пример 6.7. Использование ключевого слова final
Следует помнить, что финальными могут быть объявлены только методы и классы, к свойствам ключевое слово final не применимо.
6.4. Конструкторы и деструкторы.
При создании класса в нем можно определять специальный метод, называемый конструктором. Классы, в которых определены методы-конструкторы, вызывают их при создании каждого нового объекта, что позволяет передавать вновь создаваемым объектам начальные данные, тем самым инициализируя некоторое состояние объекта еще до начала его использования. Объявляются конструкторы при помощи специальной функции __construct() (см. пример 6.8).
<?php class fruit_color{ public $color, $fruit; //Объявляем свойства function __construct($c){ //Объявляем конструктор с одним аргументом $this->color=$c; //Задаем цвет фруктов } function set_fruit($fruit){ //Объявляем обычный метод с одним аргументом $this->fruit=$fruit; //Задаем вид фруктов echo $this->color.' '.$this->fruit.'<br>'; //Выводим цвет и вид } function __destruct(){ //Вызываем деструктор для удаления //объекта при освобождении ссылок на него } } $apples=new fruit_color('Yellow'); //Создаем объект и сразу же инициализируем $apples->set_fruit('orange'); //Вызываем метод объекта class fruit_color_2 extends fruit_color{ //Объявляем класс-потомок function __construct($c_1, $c_2){ //Объявляем свой конструктор $this->color=$c_1.' and '.$c_2; //Задаем два цвета фруктов } } $apples_2=new fruit_color_2('Red', 'yellow'); //Создаем объект класса-потомка $apples_2->set_fruit('apples'); //Вызываем метод объекта ?>
Пример 6.8. Использование конструкторов и деструкторов
В отличие от других методов, конструкторы классов-потомков разрешается переопределять с другими параметрами, отличными от тех, которые были заданы в родительском методе-конструкторе.
Если инициализированные объекты далее в программе не используются, имеет смысл удалять их для высвобождения памяти. Для этих целей в классах разрешается объявлять специальные методы, называемые деструкторами (см. пример 6.8). Они запускаются после освобождения всех ссылок на определенный объект или при завершении скрипта. Деструктор вызывается даже в том случае, когда работа скрипта останавливается при помощи функции exit() (данная функция выводит сообщение и прекращает выполнение скрипта). При чем, если функция exit() вызывается в самом деструкторе, она предотвращает запуск всех последующих функций завершения.
Следует помнить, что если класс-потомок определяет собственный конструктор/деструктор, то конструктор/деструктор родительского класса вызываться не будет. Поэтому для его вызова внутри конструктора/деструктора класса-потомка, следует использовать конструкцию parent::__construct()/ parent::__destruct(). Если же в классе-потомке собственный конструктор/деструктор не определяется, то родительский конструктор/деструктор, если конечно он не объявлен приватным, наследуется как обычный метод.
6.5. Определение области видимости свойств и методов.
Как было сказано выше, область видимости свойств и методов определяется во время объявления при помощи ключевых слов public (общедоступный), protected (защищенный) или private (закрытый). Доступ к свойствам и методам класса, объявленным как public, разрешен отовсюду, protected разрешает доступ из родительских классов и классов-потомков, а модификатор private ограничивает область видимости пределами самого класса. Использование свойств с различным уровнем доступа показано в примере 6.9.
<?php class parent_class{ protected $protected_var='protected_var '; //Доступно изнутри самого класса //и всех классов-потомков private $private_var='private_var '; //Доступно только изнутри класса function all_func(){ echo $this->protected_var.'<br>'; //Оба свойства доступны, т.к. запрашиваются echo $this->private_var.'<br>'; //изнутри класса, где были определены } } class descendant_class extends parent_class{ protected $protected_var='p_var '; //Переопределяем свойство, при этом оно //должно оставаться protected function all_func(){ //Переопределяем метод echo $this->protected_var.'<br>';//Это свойство доступно, т.к. оно protected и //запрашивается изнутри класса-потомка echo $this->private_var.'<br>'; //Ошибка, свойство доступно только изнутри //класса parent_class, где было объявлено } } $obj=new parent_class(); //Создаем экземпляр родительского класса $obj_2=new descendant_class(); //Создаем экземпляр класса-потомка $obj->all_func(); //Сработает без ошибок //$obj_2->all_func(); //Выдаст ошибку, т.к. свойство $this->private_var //неопределено в классе-потомке и доступно только изнутри //класса parent_class, где оно было объявлено //echo $obj->private_var; //Выдаст ошибку, т.к. свойство вне класса недоступно //echo $obj->protected_var; //Выдаст ошибку, т.к. свойство вне классов недоступно //echo $obj_2->private_var; //Выдаст ошибку, т.к. свойство неопределено в descendant_class ?>
Пример 6.9. Определение области видимости свойств классов
Следует помнить, что при переопределении свойств, объявленных как protected или private, область видимости свойств может быть расширена, но не уменьшена. Поэтому разрешается изменять область видимости свойства с private на protected или public, а также protected на public. Но область видимости свойств, объявленных как public, уже изменить нельзя.
В отличие от свойств, при объявлении области видимости методов ключевое слово public разрешается не указывать, т.к. в случае отсутствия такового интерпретатор по умолчанию будет рассматривать их как public. Все остальное справедливо и для методов (см. пример 6.10).
<?php class parent_class{ protected function protected_func(){ //Доступен изнутри самого класса echo 'Защищенный метод'.'<br>'; //и всех классов-потомков } private function private_func(){ //Доступен только изнутри класса echo 'Закрытый метод'.'<br>'; } function all_func(){ //Объявляем общедоступный метод $this->protected_func(); //Оба метода доступны, т.к. запрашиваются $this->private_func(); //изнутри класса, где были определены } } class descendant_class extends parent_class{ function all_func(){ //Переопределяем метод $this->protected_func(); //Этот метод доступен, т.к. он protected и //запрашивается изнутри класса-потомка $this->private_func(); //Ошибка, метод доступен только изнутри //класса parent_class, где он был объявлен } } $obj=new parent_class(); //Создаем экземпляр родительского класса $obj_2=new descendant_class(); //Создаем экземпляр класса-потомка $obj->all_func(); //Сработает без ошибок //$obj_2->all_func(); //Выдаст ошибку, т.к. метод $this->private_func() //неопределен в классе-потомке и доступен только //изнутри класса parent_class, где он был объявлен //$obj->protected_func(); //Выдаст ошибку, т.к. метод вне классов недоступен //$obj->private_func(); //Выдаст ошибку, т.к. метод вне класса недоступен ?>
Пример 6.10. Определение области видимости методов классов
6.6. Специальные виды классов.
В PHP поддерживается определение абстрактных классов и методов, т.е. некоторых наиболее общих шаблонов, которые в основном имеют описательный смысл и задают характерные особенности всех наследуемых классов-потомков. При этом, если в классе объявляется хотя бы один абстрактный метод, то и сам класс должен быть объявлен абстрактным. Также нельзя создавать экземпляры (объекты) абстрактного класса, а методы, объявленные абстрактными, не должны включать конкретной реализации. Объявляются абстрактные классы и методы при помощи служебного слова abstract (см. пример 6.11).
<?php abstract class abstract_class{ //Объявили абстрактный класс abstract protected function return_value(); //Абстрактный, т.е. без реализации abstract protected function get_name($name); //Абстрактный, т.е. 'пустой' public function common_method(){ //Обычный общий метод наследуемый return $this->return_value(); //всеми классами-потомками } } class concrete_class_1 extends abstract_class{ protected function return_value() { //Реализуем (заполняем) метод return 'Реализация метода в классе-потомке concrete_class_1'.'<br>'; } public function get_name($first_name){ //Расширяем область видимости метода return "{$first_name}".'<br>'; } } class concrete_class_2 extends abstract_class{ public function return_value(){ //Расширяем область видимости метода return 'Реализация метода в классе-потомке concrete_class_2'.'<br>'; } //Расширяем область видимости метода и добавляем ему один необязательный параметр public function get_name($first_name, $last_name=' Иванов '){ return "{$first_name} {$last_name}".'<br>'; } } $obj_1 = new concrete_class_1; //Создаем экземпляр первого класса-потомка echo $obj_1->common_method(); echo $obj_1->get_name(' Иван '); $obj_2 = new concrete_class_2; //Создаем экземпляр второго класса-потомка echo $obj_2->common_method(); echo $obj_2->get_name(' Петр '); //Используется значение по умолчанию echo $obj_2->get_name(' Петр ', ' Сидоров'); ?>
Пример 6.11. Использование абстрактных классов и методов
При наследовании от абстрактного класса все методы, объявленные абстрактными в родительском классе, должны быть определены и в классе-потомке, а их область видимости, как и в случае с обычными методами, должна оставаться той же или быть менее строгой. Например, если абстрактный метод был объявлен как protected, то область видимости реализации этого метода в классе-потомке должна быть либо protected либо public, но никак не private. Также следует помнить, что должны совпадать типы данных при использовании контроля типов и количество обязательных аргументов метода. И хотя разрешается добавлять необязательные аргументы (т.е. аргументы, которые используют значения по умолчанию), количество обязательных аргументов в любом случае должно совпадать (см. пример 6.11).
Еще одной разновидностью общих шаблонов, использующихся в PHP, являются интерфейсы. Они служат для указания методов без необходимости описывания их функционала. При этом все методы, определенные в интерфейсе, должны быть реализованы в наследующих данный интерфейс классах, иметь область видимости public (и в интерфейсе, и в классе), а их тела должны быть пустыми. Но самой важной особенностью интерфейсов является то, что классы могут реализовывать (наследовать) сразу несколько интерфейсов, перечисляемых при наследовании через запятую (соответственно, должны быть реализованы и все методы наследуемых интерфейсов).
Объявляются интерфейсы при помощи отдельного ключевого слова interface, но в случае необходимости расширения, могут быть унаследованы друг от друга также, как и обычные классы, т.е. при помощи оператора ixtends. Если же интерфейс наследуется (реализуется) обычным классом, а не другим интерфейсом, должен использоваться не оператор ixtends, а специально предназначенный для такого случая оператор implements (см. пример 6.12).
<?php interface my_intf_1{ //Объявляем первый интерфейс const c_1="Константа интерфейса 1"; //Объявляем константу интерфейса public function my_func_1($a, $b); //Метод должен принимать 2 аргумента } interface my_intf_2{ //Объявляем второй интерфейс public function my_func_2($d); //Метод должен принимать 1 аргумент } interface my_intf_3 extends my_intf_1, my_intf_2{ //Расширяем интерфейс public function my_func_3(); //Метод без аргументов } interface my_intf_4{ //Объявляем еще один интерфейс const c_4="Константа интерфейса 4"; //Объявляем константу интерфейса } class my_class implements my_intf_3, my_intf_4{ //Реализуем расширенный интерфейс const c_2="Константа класса"; //Объявляем константу класса public function my_func_1($a, $b){ //Реализуем первый метод return $a+$b; } public function my_func_2($d){ //Реализуем второй метод echo $this->my_func_1($d,5).'<br>'; } public function my_func_3(){ //Реализуем третий метод $this->my_func_4(); } private function my_func_4(){ //Объявляем закрытый метод класса echo 'Строка из my_func_4'.'<br>'; } } $obj= new my_class(); $obj->my_func_2(5); //Выведет '10' $obj->my_func_3(); //Выведет 'Строка из my_func_4' echo $obj::c_1.'<br>'.$obj::c_4.'<br>'.$obj::c_2; //Выведет все константы ?>
Пример 6.12. Использование интерфейсов
Реализовывать в одном классе два интерфейса, содержащих одноименную функцию, запрещено, т.к. это повлечет за собой неоднозначность. Кроме того, сигнатуры методов в классе, реализующем интерфейс, должны точно совпадать с сигнатурами, используемыми в интерфейсе, иначе будет вызвана ошибка.
Отметим, что интерфейсы могут также содержать константы, которые работают так же, как и константы обычных классов, за исключением того, что они не могут быть переопределены наследующим классом или интерфейсом.
Для уменьшения некоторых ограничений единого наследования в PHP используются специальные конструкции, называемые трейтами, которые представляют собой наборы свойств и методов доступных для последующего свободного и многократного использования сразу в нескольких независимых классах. Трейты очень похожи на классы, но не могут иметь собственных объектов и дают возможность использовать свои свойства и методы классами свободно без необходимости наследования (см. пример 6.13).
<?php trait tr_1{ //Трейты объявляются при помощи служебного слова trait public $var_tr_1='Свойство 1-го трейта'; //Объявили свойство трейта public function func_tr_1(){ //Объявили метод трейта echo 'Метод 1-го трейта'.'<br>'; } } trait tr_2{ //Объявили второй трейт static $var_tr_2='Статическое свойство 2-го трейта '; public static function func_tr_2(){ //Объявили статический метод трейта echo 'Статический метод 2-го трейта'.'<br>'; } } trait tr_3{ //Объявили третий трейт use tr_1, tr_2; //Подключаем первый и второй трейты public abstract function func_tr_3(); //Объявили абстрактный метод трейта } trait tr_4{ //Объявили четвертый трейт public abstract function func_tr_4(); //Объявили абстрактный метод трейта } class base_class_1{ //Объявили первый класс use tr_1; //Подключаем первый трейт public function func_bs_cl_1(){ //Объявили метод первого класса echo 'Метод класса base_class_1'.'<br>'; } } class child_class_1 extends base_class_1{ //Объявили класс-потомок первого класса use tr_2; //Подключаем второй трейт public function func_cld_cl_1(){ //Объявили метод класса echo 'Метод класса-потомка child_class_1'.'<br>'; } } class base_class_2{ //Объявили второй класс public $var_bs_cl_2='Св-во 2-го класса'; //Объявили свойство второго класса use tr_3,tr_4; //Подключаем третий и четвертый трейты public function func_tr_3(){ //Абстр. метод должен быть реализован echo 'Реализация абстр. метода func_tr_3'.'<br>'; } public function func_tr_4(){ //Абстр. метод должен быть реализован echo 'Реализация абстр. метода func_tr_4'.'<br>'; } } $obj_cld_cl_1=new child_class_1(); //Создали объект класса-потомка child_class_1 $obj_cld_cl_1->func_tr_1(); //Выведет 'Метод 1-го трейта' $obj_cld_cl_1::func_tr_2(); //Выведет 'Статический метод 2-го трейта' $obj_cld_cl_1->func_bs_cl_1(); //Выведет 'Метод класса base_class_1' $obj_cld_cl_1->func_cld_cl_1(); //Выведет 'Метод класса-потомка child_class_1' echo $obj_cld_cl_1->var_tr_1.'<br>'; //Выведет 'Свойство 1-го трейта' echo $obj_cld_cl_1::$var_tr_2.'<br>'; //Выведет 'Статическое свойство 2-го трейта' $obj_bs_cl_2=new base_class_2(); //Создали объект класса base_class_2 $obj_bs_cl_2->func_tr_3(); //Выведет 'Реализация абстр. метода func_tr_3' $obj_bs_cl_2->func_tr_4(); //Выведет 'Реализация абстр. метода func_tr_4' echo $obj_bs_cl_2->var_bs_cl_2.'<br>'; //Выведет 'Св-во 2-го класса' /* Плюс свойства и методы всех подключенных ко второму классу трейтов */ $obj_bs_cl_2->func_tr_1(); //Выведет 'Метод 1-го трейта' $obj_bs_cl_2::func_tr_2(); //Выведет 'Статический метод 2-го трейта' echo $obj_bs_cl_2->var_tr_1.'<br>'; //Выведет 'Свойство 1-го трейта' echo $obj_bs_cl_2::$var_tr_2; //Выведет 'Статическое свойство 2-го трейта' ?>
Пример 6.13. Использование трейтов
Как было показано в примере, трейты объявляются и подключаются, соответственно, при помощи ключевых слов trait и use. В случае подключения нескольких трейтов сразу, они перечисляются через запятую. При этом разрешается использовать трейты не только в классах, но и подключать их к другим трейтам, при помощи того же оператора use.
При формировании трейтов разрешается использовать абстрактные методы, а также статические свойства и методы, но объявлять константы в трейтах нельзя.
Следует помнить, что область видимости всех методов и свойств в трейтах должна быть определена как public, а далее, при использовании в классах, она может быть изменена в зависимости от конкретных потребностей класса.
В случае объявления в классе свойства с именем, совпадающим с именем свойства присутствующего в подключаемом трейте, возникнет ошибка. Тоже самое произойдет и при подключении к классу двух трейтов, имеющих методы с одинаковыми именами. Однако в этом случае ошибки можно избежать, использовав оператор insteadof, который позволяет выбрать из конфликтных методов лишь один. Если же необходимо включить в класс сразу оба метода, следует использовать один из них под другим именем при помощи оператора as, который к тому же позволяет изменить и область видимости подключаемого метода (см. пример 6.14).
<?php trait tr_1{ public $var_tr_1='Св-во трейта'; //Объявили свойство трейта public function func_a(){ //Объявили метод трейта echo 'Метод func_a 1-го трейта'.'<br>'; } public function func_b(){ //Объявили метод трейта echo 'Метод func_b 1-го трейта'.'<br>'; } } trait tr_2{ //Объявили второй трейт public function func_a(){ //Имя используется и в tr_1 echo 'Метод func_a 2-го трейта'.'<br>'; } public function func_b(){ //Имя используется и в tr_1 echo 'Метод func_b 2-го трейта'.'<br>'; } public function func_c(){ //Еще один метод 2-го трейта echo 'Метод func_c 2-го трейта'.'<br>'; } } class base_class{ //Объявили класс // public $var_tr_1='Свойство класса'; //Ошибка, свойство уже определено в трейте use tr_1, tr_2{ tr_1::func_a insteadof tr_2; //Будем использовать метод первого трейта tr_1::func_a as protected; //Переопределяем его на protected tr_2::func_b insteadof tr_1; //Будем использовать метод второго трейта tr_2::func_a as protected func_a_2;//Метод 2-го трейта используем под именем } //func_a_2 и с областью видимости protected public function func_c(){ //Объявили собственный метод класса //который переопределит метод 2-го трейта echo 'Метод класса base_class'.'<br>'; } } class child_class extends base_class{ //Объявили класс-потомок public function func_d(){ //Объявили собственный метод класса-потомка parent::func_a(); //Вызываем метод родительского класса } public function func_e(){ //Объявили еще один метод класса-потомка parent::func_a_2(); //Вызываем метод родительского класса } public function func_b(){ //Переопределяем метод родительского класса echo 'Метод класса child_class'.'<br>'; } } $obj_bs_cl=new base_class(); //Создали объект класса base_class $obj_bs_cl->func_b(); //Выведет 'Метод func_b 2-го трейта ' $obj_bs_cl->func_c(); //Выведет 'Метод класса base_class ' $obj_cld_cl=new child_class(); //Создали объект класса-потомка $obj_cld_cl->func_b(); //Выведет 'Метод класса child_class ' $obj_cld_cl->func_d(); //Выведет 'Метод func_a 1-го трейта ' $obj_cld_cl->func_e(); //Выведет 'Метод func_a 2-го трейта ' $obj_cld_cl->func_c(); //Выведет 'Метод класса base_class ' ?>
Пример 6.14. Разрешение конфликтов в трейтах
Обратите внимание, что в примере трейт, который был использован в родительском классе, не переопределяет одноименный метод этого класса. Если же трейт вставляется в класс-потомок, то методы трейта, наоборот, имеют больший приоритет и переопределяют одноименные унаследованные методы родительского класса, хотя собственные методы текущего класса-потомка они по-прежнему не переопределяют.
В PHP 7 была добавлена поддержка анонимных классов, которые могут быть полезны в случае необходимости одноразового использования, например, для возврата функцией значения в виде определенного объекта с требуемым набором свойств и методов. При этом анонимные классы могут иметь конструкторы, расширять другие классы, реализовывать интерфейсы или подключать трейты точно также, как и обычные классы (см. пример 6.15).
<?php trait tr_5_minus{ //Создаем трейт public function _5_minus($n){ //Определяем один метод echo $this->m-$n.'<br>'; } } interface int_5_mult{ //Создаем интерфейс public function _5_plus($n); //Задаем шаблон метода } $obj_5=new class(5) implements int_5_mult{ //Создаем объект анонимного класса use tr_5_minus; //Подключаем интерфейс public $m; //Объявляем свойство класса function __construct($arg){ //Объявляем конструктор класса $this->m=$arg; //Устанавливает первый член операций } public function _5_plus($n){ //Реализуем интерфейс echo $this->m+$n.'<br>'; } public function _5_mult($n){ //Создаем собственный метод echo $this->m*$n.'<br>'; } }; //Не забываем про точку с запятой!!! $obj_5->_5_minus(6); //Выведет '-1' $obj_5->_5_plus(6); //Выведет '11' $obj_5->_5_mult(6); //Выведет '30' ?>
Пример 6.15. Анонимные классы
Анонимные классы могут использоваться также внутри других классов. При этом в общем случае у них отсутствует доступ к свойствам и методам внешнего класса, которые имеют область видимости private или protected. Поэтому, чтобы получить доступ к ним, анонимный класс должен расширять внешний класс. В этом случае закрытые и защищенные методы становятся доступны напрямую, а свойства должны передаваться анонимному классу через его конструктор (см. пример 6.16).
<?php class outer_class{ //Создаем внешний класс protected $n_out=2; //Объявили свойство внешнего класса public function func_ins_1(){ //Определяем первый метод outer_class //Здесь $this представляет внешний класс echo (new class($this->n_out) extends outer_class{ public $n_ins; //Объявили свойство анонимного класса function __construct($arg){ //А здесь $this уже относится к анонимному классу $this->n_ins=$arg*$arg; } })->n_ins;.'<br>' //И сразу же обращаемся к свойству созданного } //объекта анонимного класса public function func_ins_2(){ //Определяем второй метод outer_class //Здесь $this представляет внешний класс return new class($this->n_out) extends outer_class{ const a=5; //Объявили константу анонимного класса public $n_ins; //Объявили свойство анонимного класса function __construct($arg){ //А здесь $this уже относится к анонимному классу $this->n_ins=$arg*$arg; } }; //Возвращаем готовый анонимный объект } } $obj=new outer_class(); $obj->func_ins_1(); //Выведет '4' echo $obj->func_ins_2()->n_ins.'<br>'; //Выведет '4' echo $obj->func_ins_2()::a; //Выведет '5' ?>
Пример 6.16. Использование анонимных классов внутри других классов
Таким образом, конструкция (new class(){}); представляет собой неименованный объект с определенным набором свойств и методов, который может быть использован как сразу в паре с различными операторами, например, echo или return, так и сохранен в обычной переменной для доступа к его свойствам и методам позднее.
6.7. Операции с объектами.
При работе с объектами может возникнуть необходимость в последовательном перечислении свойств текущего объекта. В этом случае может пригодиться известный нам цикл foreach, который позволяет получить доступ ко всем открытым для него свойствам и их значениям (см. пример 6.17).
<?php class iter_class{ public $var_1='value_1'; //Общедоступное public $var_2='value_2'; //Общедоступное protected $protected_var='protected_var'; //Защищенное private $private_var='private_var'; //Закрытое function iterate_properties(){ //Метод для перечисления свойств echo "Свойства класса iter_class, перечисляемые циклом изнутри класса:<br>"; foreach($this as $key=>$value){ //Перечисляем внутри класса echo "{$key}=>{$value}".'<br>'; } } } $class = new iter_class(); $class->iterate_properties(); echo "<br> Свойства класса iter_class, перечисляемые циклом снаружи класса:<br>"; foreach($class as $key=>$value){ //Перечисляем снаружи класса echo "{$key}=>{$value}".'<br>'; } ?>
Пример 6.17. Перечисление свойств объектов циклом foreach
Как видим, цикл foreach перечисляет все доступные для него в данной области видимости свойства объекта так, как-будто он имеет дело с обычным массивом.
Возможности PHP по итерации объектов не исчерпываются только лишь циклом foreach, поскольку для этих целей имеются также и специальные интерфейсы, позволяющие реализовывать итерацию объектов практически любым удобным для программиста способом. Однако здесь мы их рассматривать не будем, а вернемся к этому вопросу во второй части учебника.
Также как и другие типы данных, объекты можно сравнивать между собой. При использовании оператора нестрогого сравнения '==' два объекта будут считаться равными, если они являются экземплярами одного и того же класса и имеют один и тот же набор свойств и соответствующих им значений. А в случае использования оператора идентичности '===', объекты будут считаться тождественно равными (идентичными) только тогда, когда они ссылаются на один и тот же экземпляр одного и того же класса (см. пример 6.18).
<?php class my_class_1{ public $var_1='value_1'; //Общедоступное protected $protected_var='protected_var'; //Защищенное public function func(){ //Метод класса echo 'Функция func'; } } class my_class_2{ public $var_1='value_1'; //Общедоступное protected $protected_var='protected_var'; //Защищенное public function func(){ //Метод класса echo 'Функция func'; } } $obj_1=new my_class_1(); //Создаем объекты одного $obj_2=new my_class_1(); //и того же класса echo $obj_1==$obj_2; //Выведет '1' (т.е. true), т.к. объекты принадлежат //одному классу, имеют одинаковые свойства и их значения echo $obj_1===$obj_2; //Выведет '' (т.е. false), т.к. объекты принадлежат //одному классу, но являются разными экземплярами $obj_2->var_1='new value'; //Изменим значение свойства второго объекта echo $obj_1==$obj_2; //Выведет '' (т.е. false), т.к. объекты принадлежат //одному классу, имеют одинаковые свойства, но //значения одного из них ($var_1) различаются $obj_3=$obj_1; echo $obj_3===$obj_1; //Выведет '1' (т.е. true), т.к. переменные содержат //ссылки на один и тот же экземпляр (new my_class_1) $obj_4=new my_class_2(); //Создаем объект другого класса echo $obj_4==$obj_1; //Выведет '' (т.е. false), т.к. объекты принадлежат //разным классам ?>
Пример 6.18. Сравнение объектов
Отметим, что расширения могут определять собственные правила для сравнения своих объектов.
Как говорилось выше, когда мы присваиваем одну переменную, содержащую идентификатор какого-нибудь объекта, другой переменной, мы получаем две переменные, содержащие один и тот же идентификатор, указывающий на один и тот же объект. Если же нам необходимо создать именно копию объекта, а не копию его идентификатора, то необходимо воспользоваться оператором clone, который создаст объект с полностью идентичными свойствами, которые можно изменить по своему усмотрению при помощи метода __clone, вызывающегося только при каждом новом клонировании объекта (см. пример 6.19).
<?php class cloneable_class{ public $var_1=0; //Создаем свойство public function __construct(){ //Каждый раз при создании нового объекта ++$this->var_1; //$var_1 будет увеличиваться на 1 } public function __clone(){ //Метод запускается только при клонировании ++$this->var_1; //объекта и увеличивает $var_1 на 1 } } $obj_1 = new cloneable_class(); //Создаем объект класса cloneable_class //Теперь просто копируем идентификатор, который указывает на new cloneable_class(), //при этом метод __clone не запускается $obj_2=$obj_1; echo $obj_1->var_1.'<br>'; //Выведет '1' echo $obj_2->var_1.'<br>'; //Выведет '1' $obj_1->var_1=5; //Изменили значение свойства на 5 echo $obj_2->var_1.'<br>'; //Выведет '5', т.к. обе переменные ссылаются //на один и тот же объект //Клонируем $obj_1, при этом создается реальный объект-клон с запуском метода__clone $obj_3=clone $obj_1; echo $obj_1->var_1.'<br>'; //Выведет '5' echo $obj_3->var_1.'<br>'; //Выведет '6' $obj_1->var_1=10; //Изменили значение исходного объекта на 10 echo $obj_3->var_1; //Выведет по-прежнему '6', т.к. переменные $obj_3 //и $obj_1 ссылаются на разные объекты ?>
Пример 6.19. Клонирование объектов
Таким образом, если мы собираемся клонировать объект и хотим при клонировании изменить некоторые его свойства, то необходимо заранее в исходном классе объявить метод __clone, который будет вызываться по завершении каждого нового процесса клонирования объекта. При этом нужно помнить, что вызов данного метода не может быть выполнен непосредственно. В случае отсутствия метода __clone в исходном объекте в результате клонирования будет создана простая неизмененная копия объекта. В любом случае после создания клон станет доступным для независимого использования.
6.8. Перегрузка в PHP.
Под перегрузкой в программировании подразумевается возможность использования функций и методов, имеющих одинаковые имена. Однако в PHP понятие 'перегрузки' интерпретируется не так, как в других объектно-ориентированных языках. В PHP перегрузка означает возможность получения доступа при помощи специальных методов перегрузки, называемых еще магическими или волшебными методами, к недоступным обычными способами свойствам или методам. К таковым относятся свойства и методы, которые не были объявлены или не видны в текущей области видимости. При этом методы перегрузки, объявляемые в текущем классе, должны иметь область видимости public, не могут принимать аргументы по ссылке и вызываются только в случае обращения к указанным свойствам или методам. Перечислим методы перегрузки, имеющиеся в PHP:
- __set($name, $value) – выполняется при записи данных в недоступные свойства; здесь аргумент $name представляет собой имя вызываемого свойства, а $value – значение, которое будет записано в данное свойство;
- __get($name) – выполняется при чтении данных из недоступных свойств; здесь аргумент $name представляет собой имя вызываемого свойства;
- __isset($name) – выполняется при использовании функций isset() или empty() на недоступных свойствах; здесь аргумент $name представляет собой имя вызываемого свойства;
- __unset($name) – выполняется при вызове unset() на недоступном свойстве; здесь аргумент $name представляет собой имя вызываемого свойства;
- __call($name, $arguments) – вызывается в контексте объекта при вызове недоступных методов; здесь аргумент $name представляет собой имя вызываемого метода, $arguments – числовой массив, содержащий параметры, передаваемые вызываемому методу;
- __callStatic($name, $arguments) – вызывается в статическом контексте при вызове недоступных методов; здесь аргумент $name представляет собой имя вызываемого метода, $arguments – числовой массив, содержащий параметры, передаваемые вызываемому методу.
Отметим, что функция isset(), определяет установлена ли переменная, переданная ей в качестве аргумента, значением отличным от null, а функция empty() проверяет, считается ли переменная пустой (переменная считается пустой, если она не существует или её значение равно false). Что касается функции unset(), то она удаляет переменную, переданную ей в качестве аргумента. К данным функциям мы вернемся во второй части учебника. Теперь же рассмотрим пример 6.20, в котором показаны некоторые ситуации перегрузки свойств.
<?php class my_class{ public $var_1=5; //К доступным свойствам перегрузка не применяется private $private_var_1=10; //В отношении закрытых свойств методы перегрузки private $private_var_2; //вызываются только при доступе вне класса, где //они недоступны обычными способами //Метод автоматически вызывается в случае обращения к недоступным свойствам public function __set($name, $value){ $this->$name=$value; //Устанавливаем значение недоступного свойства } //Метод возвращает значение недоступного свойства, если оно установлено, //или выводит сообщение, если такого свойства нет или оно не инициализировано public function __get($name){ //Если переменная установлена значением отличным от null if(isset($this->$name)){ return $this->$name;//возвращаем значение недоступного свойства }else{ echo "Свойство {$name} отсутствует или не определено в данном классе."; } } public function __isset($name){ return isset($this->$name); //возвращаем результат вызова функции isset(), } //вызванной для недоступного свойства public function __unset($name){ unset($this->$name); //удаляем недоступное свойство } } $obj_1=new my_class(); //Создаем объект класса my_class echo $obj_1->private_var_1.'<br>'; //Выведет 10, что возможно благодаря определенному //в классе методу перегрузки __get() $obj_1->private_var_1=20; //Изменяем значение закрытого свойства вне класса, //что возможно благодаря методу перегрузки __set() echo $obj_1->private_var_1.'<br>'; //Выведет 20 echo isset($obj_1->private_var_1).'<br>'; //Выведет '1', т.е. true unset($obj_1->private_var_1); //Удаляем закрытое свойство вне класса, что стало //возможным благодаря методу перегрузки __unset() echo isset($obj_1->private_var_1).'<br>'; //Выведет '', т.е. false - свойство удалено echo $obj_1->private_var_2.'<br>'; //Метод перегрузки __get() выведет сообщение $obj_1->private_var_2=5; //Устанавливаем значение закрытого св-ва вне класса echo $obj_1->private_var_2.'<br>'; //Выведет 5 echo $obj_1->private_var_3.'<br>'; //Метод перегрузки __get() выведет сообщение ?>
Пример 6.20. Перегрузка свойств
Как видим, методы перегрузки позволяют нам получить доступ, например, к приватным и защищенным свойствам, которые в обычных условиях недоступны при обращении к ним вне класса. Однако следует помнить, что перегрузка свойств работает только в контексте объекта, поэтому соответствующие им методы перегрузки не могут быть объявлены статичными и не вызываются при попытке обращения к недоступным статическим свойствам.
Что касается последних двух методов перегрузки, то первый из них предназначен для работы с недоступными методами в контексте объекта, а второй – для работы с недоступными статическими методами (см. пример 6.21).
<?php class my_class{ private function my_func(){ //Определяем частный метод echo 'Получен доступ к частной функции!'.'<br>'; } //Определяем статический частный метод private static function static_func(){// echo 'Получен доступ к статической частной функции!'.'<br>'; } //Определяем метод перегрузки public function __call($name, $arguments){ $this->my_func(); } //Определяем метод перегрузки в статическом контексте public static function __callStatic($name, $arguments){ self::static_func(); } } $obj_1=new my_class(); //Создаем объект класса my_class echo $obj_1->my_func(); //Выведет строку функции my_func() благодаря //определению в классе метода перегрузки __call() echo $obj_1::static_func(); //Выведет строку функции my_func() благодаря //наличию метода перегрузки __callStatic() ?>
Пример 6.21. Перегрузка методов
6.9. Позднее статическое связывание.
В PHP статические ссылки на текущий класс, такие как self::, вычисляются исходя из области видимости того класса, в котором они были определены, а не вызваны. Поэтому при наследовании методов с такими ссылками может возникнуть ситуация, когда нужно будет использовать область видимости класса-потомка, вызывающего данный метод, а не область видимости родительского класса. Для таких случаев предусмотрена возможность позднего статического связывания, заключающаяся в использовании вместо конструкции self:: специальной конструкции static::, которая отслеживает и ссылается на текущую область видимости (см. пример 6.22).
<?php class A{ public static function my_func_1(){ echo 'Класс А'.'<br>'; } public static function my_func_2(){ self::my_func_1(); } } class B extends A { public static function my_func_1(){ //Переопределяем метод echo 'Класс B'.'<br>'; } } B::my_func_2(); //Выведет 'Класс А', т.к. функция my_func_2 использует //статическую ссылку self::, которая использует область видимости //того класса, в котором она была определена, а не используется //Используем позднее статическое связывание class C{ public static function my_func_1(){ echo 'Класс C'; } public static function my_func_2(){ static::my_func_1(); } } class D extends C { public static function my_func_1(){ //Переопределяем метод echo 'Класс D'; } } D::my_func_2();//Выведет 'Класс D', т.к. функция my_func_2 использует позднее //статическое связывание при помощи ссылки static::, которая использует //область видимости класса, в котором она используется, а не определена ?>
Пример 6.22. Использование позднего статического связывания
Конструкция static::, использующаяся для позднего статического связывания, предназначена для ссылки на статические поля (т.е. свойства и методы) класса. Поэтому, во избежание получения результатов отличных от ожидаемых, не следует использовать ее в нестатическом контексте.
Контрольные вопросы и задания
- Дайте определение классу, объекту. Как создать объект?
- Опишите механизм сохранения объектов в переменных.
- Что называют свойствами и методами класса? Как создаются константы классов?
- Каким образом осуществляется доступ к свойствам, методам и константам класса после создания его экземпляров?
- Для чего используется псевдопеременная $this?
- Как и для чего создаются статические свойства и методы?
- Что понимается под процессом наследования? Как создаются классы классы-потомки?
- Для чего применяются конструкции self:: и parent::?
- Как убрать возможность дальнейшего переопределения методов или сделать класс недоступным для наследования?
- Опишите конструкторы и деструкторы классов.
- Как определяется область видимости свойства, метода?
- Опишите абстрактные классы, интерфейсы, трейты.
- Какие классы называют анонимными? Опишите их синтаксис и особенности использования.
- В чем заключается отличие операции клонирования объекта от обычного присвоения объекта переменным?
- Что называют перегрузкой в PHP? Перечислите методы перегрузки имеющиеся в PHP.
- Для чего используется конструкция static::?
Словарь новых английских слов
one-off [wʌnˈɒf] – одноразовый. partial [ˈpɑːʃ(ə)l] – частичный. class [klɑːs] – класс. new [njuː] – новый. empty [ˈempti] – пустой. constant [ˈkɒnst(ə)nt] – константа. person [ˈpəːs(ə)n] – личность, персона. object [ˈɒbdʒɪkt] – объект. method [ˈmɛθəd] – метод. property [ˈprɒpəti] – свойство. public [ˈpʌblɪk] – открытый, общественный. protected [prəˈtektɪd] – защищенный. private [ˈprʌɪvət] – закрытый, частный. this [ðɪs] – это, этот. static [ˈstatɪk] – статичный, неподвижный. extend [ɪkˈstɛnd] – расширять. self [self] – собственный. parent [ˈpɛːr(ə)nt] – родитель, предок. exit [ˈeksɪt] – выход, выйти. |
nest [nest] – вставлять один предмет в другой. final [ˈfʌɪn(ə)l] – заключительный, окончательный. construct [kənˈstrʌkt] – создавать, конструировать. destruct [dɪˈstrʌkt] – разрушать, уничтожать. descendant [dɪˈsɛnd(ə)nt] – потомок. abstract [ˈæbstrækt] – абстрактный, отвлеченный. interface [ˈɪntəfeɪs] – интерфейс, область контакта. implement [ˈɪmplɪment] – осуществлять, реализовывать. trait [treɪt] – особенность, черта. use [ˈjuːs] – употреблять, использовать. instead [ɪnˈstɛd] – вместо, взамен. as [æz] – как. anonymous [əˈnɒnɪməs] – безымянный, анонимный. clone [kləʊn] – клон, двойник. set [set] – устанавливать. unset [ʌnˈsɛt] – удалять. get [ɡet] – получать. call [kɔːl] – вызывать, звать. |