Вызов конструктора базового класса php

Обновлено: 15.07.2024

В предыдущей статье мы рассмотрели основные концепции класса и объектов. В этом руководстве по PHP вы изучите конструктор и деструктор в классе PHP.

Что такое конструктор и деструктор в классе PHP?

Конструктор

Как следует из названия, конструкция создает объект. Настоящее определение конструктора таково, что он инициализирует объект класса.

Как объявить конструктор в PHP?

Чтобы объявить конструктор в PHP, используйте двойное подчеркивание (__) вместе со словом конструкция. Убедитесь, что имя конструктора должно быть «конструктор».

Например

  • В приведенном выше примере мы создаем конструктор, используя двойные подчеркивания.
  • Мы создаем объект, который автоматически использует конструктор и инициализируем его с помощью Cat.
  • Нам не нужно вызывать функцию set_name для установки имени в объекте cat.

Итак, из приведенного выше обсуждения становится ясно, что конструктор упрощает инициализацию объекта и не требует для этого никаких функций-установщиков.

Еще примеры конструктора и деструктора в PHP

  • В приведенном выше примере мы создаем конструктор с двумя параметрами и инициализируем атрибуты nick_name и color класса этими параметрами.
  • Мы создаем новый объект cat и передаем два параметра, требуемых конструктору. Убедитесь, что для создания объекта требуется количество параметров в соответствии с конструктором класса, к которому он принадлежит.
  • После создания объекта мы протестировали его, вызвав установщики get_name и get_color класса. Он выведет имя объекта «кошка» как «кошка» и его цвет как «коричневый».

Вы можете найти ссылку на официальную документацию конструктора в PHP. здесь.

Важное понятие о конструкторе

ООП позволяет использовать механизм наследования, с помощью которого дочерний класс может расширять базовый класс или родительский класс. Мы рассмотрим его подробно, а пока нам просто нужно его описание, чтобы понять концепцию. Если дочерний класс расширяет родительский класс и хочет вызвать конструктор родительского класса в своем собственном конструкторе, просто используйте parent :: construcor_name внутри его конструктора.

Если дочерний класс не содержит своего конструктора, то конструктор базового или родительского класса наследуется как обычная функция, если не объявлен как закрытый.

Как объявить параметр по умолчанию в конструкторе?

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

  • В приведенном выше примере $ y присвоено значение по умолчанию 0.
  • Если объект $ obj = new class (2) создан, значение y по умолчанию будет установлено конструктором равным 0.

разрушитель

Основная цель деструктора - уничтожить или удалить объект из памяти после остановки выполнения программы или завершения процесса.

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

Посмотрите на следующий пример объявления деструктора в PHP

Еще один пример деструктора

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

Деструкторы выглядят просто с точки зрения реализации. Однако они играют жизненно важную роль в защите памяти от утечки.

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

Вы можете найти ссылку на официальную документацию деструктора в PHP здесь.

Каждое определение класса начинается с ключевого слова class , затем следует имя класса, и далее пара фигурных скобок, которые заключают в себе определение свойств и методов этого класса.

Именем класса может быть любое слово, при условии, что оно не входит в список зарезервированных слов PHP, начинается с буквы или символа подчёркивания и за которым следует любое количество букв, цифр или символов подчёркивания. Если задать эти правила в виде регулярного выражения, то получится следующее выражение: ^[a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*$ .

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

class SimpleClass
// объявление свойства
public $var = 'значение по умолчанию' ;

// объявление метода
public function displayVar () echo $this -> var ;
>
>
?>

Псевдопеременная $this доступна в том случае, если метод был вызван в контексте объекта. $this - значение вызывающего объекта.

Вызов нестатического метода статически вызывает ошибку Error . До PHP 8.0.0 это привело бы к уведомлению об устаревании, и $this не была бы определена.

class A
function foo ()
if (isset( $this )) echo '$this определена (' ;
echo get_class ( $this );
echo ")\n" ;
> else echo "\$this не определена.\n" ;
>
>
>

$a = new A ();
$a -> foo ();

$b = new B ();
$b -> bar ();

Результат выполнения данного примера в PHP 7:

Результат выполнения данного примера в PHP 8:

Для создания экземпляра класса используется директива new . Новый объект всегда будет создан, за исключением случаев, когда он содержит конструктор, в котором определён вызов исключения в случае возникновения ошибки. Рекомендуется определять классы до создания их экземпляров (в некоторых случаях это обязательно).

Если с директивой new используется строка ( string ), содержащая имя класса, то будет создан новый экземпляр этого класса. Если имя находится в пространстве имён, то оно должно быть задано полностью.

Замечание:

В случае отсутствия аргументов в конструктор класса, круглые скобки после названия класса можно опустить.

// Это же можно сделать с помощью переменной:
$className = 'SimpleClass' ;
$instance = new $className (); // new SimpleClass()
?>

Начиная с PHP 8.0.0, поддерживается использование оператора new с произвольными выражениями. Это позволяет создавать более сложные экземпляры, если выражение представлено в виде строки ( string ). Выражения должны быть заключены в круглые скобки.

В данном примере мы показываем несколько вариантов допустимых произвольных выражений, которые представляют имя класса. Пример вызова функции, конкатенации строк и константы ::class .

class ClassA extends \ stdClass <>
class ClassB extends \ stdClass <>
class ClassC extends ClassB <>
class ClassD extends ClassA <>

function getSomeClass (): string
return 'ClassA' ;
>

var_dump (new ( getSomeClass ()));
var_dump (new ( 'Class' . 'B' ));
var_dump (new ( 'Class' . 'C' ));
var_dump (new ( ClassD ::class));
?>

Результат выполнения данного примера в PHP 8:

В контексте класса можно создать новый объект через new self и new parent .

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

$instance = new SimpleClass ();

$assigned = $instance ;
$reference =& $instance ;

$instance -> var = '$assigned будет иметь это значение' ;

$instance = null ; // $instance и $reference становятся null

var_dump ( $instance );
var_dump ( $reference );
var_dump ( $assigned );
?>

Результат выполнения данного примера:

Создавать экземпляры объекта можно двумя способами:

class Test
static public function getNew ()
return new static;
>
>

class Child extends Test
<>

$obj1 = new Test ();
$obj2 = new $obj1 ;
var_dump ( $obj1 !== $obj2 );

$obj3 = Test :: getNew ();
var_dump ( $obj3 instanceof Test );

$obj4 = Child :: getNew ();
var_dump ( $obj4 instanceof Child );
?>

Результат выполнения данного примера:

Обратиться к свойству или методу только что созданного объекта можно с помощью одного выражения:

Результатом выполнения данного примера будет что-то подобное:

Замечание: До PHP 7.1 аргументы не имели значения, если не определена функция конструктора.

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

Свойства и методы класса живут в разделённых "пространствах имён", так что возможно иметь свойство и метод с одним и тем же именем. Ссылки как на свойства, так и на методы имеют одинаковую нотацию, и получается, что получите вы доступ к свойству или же вызовете метод - определяется контекстом использования.

public function bar () return 'метод' ;
>
>

$obj = new Foo ();
echo $obj -> bar , PHP_EOL , $obj -> bar (), PHP_EOL ;

Результат выполнения данного примера:

Это означает, что вызвать анонимную функцию, присвоенную переменной, напрямую не получится. Вместо этого свойство должно быть назначено, например, переменной. Можно вызвать такое свойство напрямую, заключив его в скобки.

public function __construct () $this -> bar = function() return 42 ;
>;
>
>

echo ( $obj -> bar )(), PHP_EOL ;

Результат выполнения данного примера:

extends

Класс может наследовать константы, методы и свойства другого класса используя ключевое слово extends в его объявлении. Невозможно наследовать несколько классов, один класс может наследовать только один базовый класс.

Наследуемые константы, методы и свойства могут быть переопределены (за исключением случаев, когда метод или константа класса объявлены как final) путём объявления их с теми же именами, как и в родительском классе. Существует возможность доступа к переопределённым методам или статическим свойствам путём обращения к ним через parent::

Замечание: Начиная с PHP 8.1.0, константы можно объявлять окончательными (final).

class ExtendClass extends SimpleClass
// Переопределение метода родителя
function displayVar ()
echo "Расширенный класс\n" ;
parent :: displayVar ();
>
>

$extended = new ExtendClass ();
$extended -> displayVar ();
?>

Результат выполнения данного примера:

Правила совместимости сигнатуры

При переопределении метода его сигнатура должна быть совместима с родительским методом. В противном случае выдаётся фатальная ошибка или, до PHP 8.0.0, генерируется ошибка уровня E_WARNING . Сигнатура является совместимой, если она соответствует правилам контравариантности, делает обязательный параметр необязательным и если какие-либо новые параметры являются необязательными. Это известно как принцип подстановки Барбары Лисков или сокращённо LSP. Правила совместимости не распространяются на конструктор и сигнатуру private методов, они не будут выдавать фатальную ошибку в случае несоответствия сигнатуры.

class Base
public function foo ( int $a ) echo "Допустимо\n" ;
>
>

class Extend1 extends Base
function foo ( int $a = 5 )
parent :: foo ( $a );
>
>

class Extend2 extends Base
function foo ( int $a , $b = 5 )
parent :: foo ( $a );
>
>

$extended1 = new Extend1 ();
$extended1 -> foo ();
$extended2 = new Extend2 ();
$extended2 -> foo ( 1 );

Результат выполнения данного примера:

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

class Base
public function foo ( int $a = 5 ) echo "Допустимо\n" ;
>
>

class Extend extends Base
function foo ()
parent :: foo ( 1 );
>
>

Результат выполнения данного примера в PHP 8 аналогичен:

class Base
public function foo ( int $a = 5 ) echo "Допустимо\n" ;
>
>

class Extend extends Base
function foo ( int $a )
parent :: foo ( $a );
>
>

Результат выполнения данного примера в PHP 8 аналогичен:

Переименование параметра метода в дочернем классе не является несовместимостью сигнатуры. Однако это не рекомендуется, так как приведёт к Error во время выполнения, если используются именованные аргументы.

class A public function test ( $foo , $bar ) <>
>

class B extends A public function test ( $a , $b ) <>
>

// Передача параметров согласно контракту A::test()
$obj -> test ( foo : "foo" , bar : "bar" ); // ОШИБКА!

Результатом выполнения данного примера будет что-то подобное:

::class

Ключевое слово class используется для разрешения имени класса. Чтобы получить полное имя класса ClassName , используйте ClassName::class . Обычно это довольно полезно при работе с классами, использующими пространства имён.

Результат выполнения данного примера:

Замечание:

Разрешение имён класса с использованием ::class происходит на этапе компиляции. Это означает, что на момент создания строки с именем класса автозагрузки класса не происходит. Как следствие, имена классов раскрываются, даже если класс не существует. Ошибка в этом случае не выдаётся.

Результат выполнения данного примера:

Начиная с PHP 8.0.0, константа ::class также может использоваться для объектов. Это разрешение происходит во время выполнения, а не во время компиляции. То же самое, что и при вызове get_class() для объекта.

Результат выполнения данного примера:

Методы и свойства Nullsafe

Начиная с PHP 8.0.0, к свойствам и методам можно также обращаться с помощью оператора "nullsafe": ?-> . Оператор nullsafe работает так же, как доступ к свойству или методу, как указано выше, за исключением того, что если разыменование объекта выдаёт null , то будет возвращён null , а не выброшено исключение. Если разыменование является частью цепочки, остальная часть цепочки пропускается.

Аналогично заключению каждого обращения в is_null() , но более компактный.

// Начиная с PHP 8.0.0, эта строка:
$result = $repository ?-> getUser ( 5 )?-> name ;

// Эквивалентна следующему блоку кода:
if ( is_null ( $repository )) $result = null ;
> else $user = $repository -> getUser ( 5 );
if ( is_null ( $user )) $result = null ;
> else $result = $user -> name ;
>
>
?>

Замечание:

Оператор nullsafe лучше всего использовать, когда null считается допустимым и ожидаемым значением для возвращаемого свойства или метода. Для индикации ошибки предпочтительнее выбрасывать исключение.

User Contributed Notes 13 notes

I was confused at first about object assignment, because it's not quite the same as normal assignment or assignment by reference. But I think I've figured out what's going on.

First, think of variables in PHP as data slots. Each one is a name that points to a data slot that can hold a value that is one of the basic data types: a number, a string, a boolean, etc. When you create a reference, you are making a second name that points at the same data slot. When you assign one variable to another, you are copying the contents of one data slot to another data slot.

Now, the trick is that object instances are not like the basic data types. They cannot be held in the data slots directly. Instead, an object's "handle" goes in the data slot. This is an identifier that points at one particular instance of an obect. So, the object handle, although not directly visible to the programmer, is one of the basic datatypes.

What makes this tricky is that when you take a variable which holds an object handle, and you assign it to another variable, that other variable gets a copy of the same object handle. This means that both variables can change the state of the same object instance. But they are not references, so if one of the variables is assigned a new value, it does not affect the other variable.

// Assignment of an object
Class Object public $foo = "bar" ;
>;

$objectVar = new Object ();
$reference =& $objectVar ;
$assignment = $objectVar

//
// $objectVar --->+---------+
// |(handle1)----+
// $reference --->+---------+ |
// |
// +---------+ |
// $assignment -->|(handle1)----+
// +---------+ |
// |
// v
// Object(1):foo="bar"
//
?>

$assignment has a different data slot from $objectVar, but its data slot holds a handle to the same object. This makes it behave in some ways like a reference. If you use the variable $objectVar to change the state of the Object instance, those changes also show up under $assignment, because it is pointing at that same Object instance.

$objectVar -> foo = "qux" ;
print_r ( $objectVar );
print_r ( $reference );
print_r ( $assignment );

//
// $objectVar --->+---------+
// |(handle1)----+
// $reference --->+---------+ |
// |
// +---------+ |
// $assignment -->|(handle1)----+
// +---------+ |
// |
// v
// Object(1):foo="qux"
//
?>

But it is not exactly the same as a reference. If you null out $objectVar, you replace the handle in its data slot with NULL. This means that $reference, which points at the same data slot, will also be NULL. But $assignment, which is a different data slot, will still hold its copy of the handle to the Object instance, so it will not be NULL.

$objectVar = null ;
print_r ( $objectVar );
print_r ( $reference );
print_r ( $assignment );

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

Замечание: Конструкторы в классах-родителях не вызываются автоматически, если класс-потомок определяет собственный конструктор. Чтобы вызвать конструктор, объявленный в родительском классе, следует обратиться к методу parent::__construct() внутри конструктора класса-потомка. Если в классе-потомке не определен конструктор, то он может наследоваться от родительского класса как обычный метод (если он не определен как приватный).

class BaseClass function __construct () print "Конструктор класса BaseClass\n" ;
>
>

class SubClass extends BaseClass function __construct () parent :: __construct ();
print "Конструктор класса SubClass\n" ;
>
>

class OtherSubClass extends BaseClass // inherits BaseClass's constructor
>

// In BaseClass constructor
$obj = new BaseClass ();

// In BaseClass constructor
// In SubClass constructor
$obj = new SubClass ();

// In BaseClass constructor
$obj = new OtherSubClass ();
?>

В целях обратной совместимости, если PHP 5 не может обнаружить объявленный метод __construct() и этот метод не наследуется от родительских классов, то вызов конструктора произойдет по устаревшей схеме, через обращение к методу, имя которого соответствует имени класса. Может возникнуть только одна проблема совместимости старого кода, если в нём присутствуют классы с методами __construct(), использующиеся для других целей.

В отличие от других методов, PHP не будет генерировать ошибку уровня E_STRICT , если __construct() будет перекрыт методом с другими параметрами, отличными от тех, которые находятся в родительском __construct().

Начиная с версии PHP 5.3.3, методы с именами, совпадающими с последним элементом имени класса, находящимся в пространстве имен, больше не будут считаться конструкторами. Это изменение не влияет на классы, не находящиеся в пространстве имен.

namespace Foo ;
class Bar public function Bar () // конструктор в версиях PHP 5.3.0-5.3.2
// обычный метод, начиная с версии PHP 5.3.3
>
>
?>

Деструкторы

PHP 5 предоставляет концепцию деструкторов, сходную с теми, что применяются в других ОО языках, таких, как C++. Деструктор будет вызван при освобождении всех ссылок на определенный объект или при завершении скрипта (порядок выполнения деструкторов не гарантируется).

class MyDestructableClass function __construct () print "Конструктор\n" ;
$this -> name = "MyDestructableClass" ;
>

function __destruct () print "Уничтожается " . $this -> name . "\n" ;
>
>

$obj = new MyDestructableClass ();
?>

Как и в случае с конструкторами, деструкторы, объявленные в родительском классе, не будут вызваны автоматически. Для вызова деструктора, объявленном в классе-родителе, следует обратиться к методу parent::__destruct() в теле деструктора-потомка. Также класс-потомок может унаследовать деструктор из родительского класса, если он не определен в нем.

Деструктор будет вызван даже в том случае, если скрипт был остановлен с помощью функции exit() . Вызов exit() в деструкторе предотвратит запуск всех последующих функций завершения.

Замечание:

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

Каждое определение класса начинается с ключевого слова class, затем следует имя класса, и далее пара фигурных скобок, которые заключают в себе определение свойств и методов этого класса.

Именем класса может быть любое слово, при условии, что оно не входит в список зарезервированных слов PHP, начинается с буквы или символа подчеркивания и за которым следует любое количество букв, цифр или символов подчеркивания. Если задать эти правила в виде регулярного выражения, то получится следующее выражение: ^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$.

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

class SimpleClass
// объявление свойства
public $var = 'значение по умолчанию' ;

// объявление метода
public function displayVar () echo $this -> var ;
>
>
?>

Псевдо-переменная $this доступна в том случае, если метод был вызван в контексте объекта. $this является ссылкой на вызываемый объект. Обычно это тот объект, которому принадлежит вызванный метод, но может быть и другой объект, если метод был вызван статически из контекста другого объекта. Это показано на следующих примерах:

class A
function foo ()
if (isset( $this )) echo '$this определена (' ;
echo get_class ( $this );
echo ")\n" ;
> else echo "\$this не определена.\n" ;
>
>
>

class B
function bar ()
// Замечание: следующая строка вызовет предупреждение, если включен параметр E_STRICT.
A :: foo ();
>
>

$a = new A ();
$a -> foo ();

// Замечание: следующая строка вызовет предупреждение, если включен параметр E_STRICT.
A :: foo ();
$b = new B ();
$b -> bar ();

// Замечание: следующая строка вызовет предупреждение, если включен параметр E_STRICT.
B :: bar ();
?>

Результат выполнения данного примера:

Для создания экземпляра класса используется директива new. Новый объект всегда будет создан, за исключением случаев, когда он содержит конструктор, в котором определен вызов исключения в случае ошибки. Рекомендуется определять классы до создания их экземпляров (в некоторых случаях это обязательно).

Если с директивой new используется строка ( string ), содержащая имя класса, то будет создан новый экземпляр этого класса. Если имя находится в пространстве имен, то оно должно быть задано полностью.

// Это же можно сделать с помощью переменной:
$className = 'Foo' ;
$instance = new $className (); // Foo()
?>

В контексте класса можно создать новый объект через new self и new parent.

Когда происходит присвоение уже существующего экземпляра класса новой переменной, то эта переменная будет указывать на этот же экземпляр класса. Тоже самое происходит и при передаче экземпляра класса в функцию. Копию уже созданного объекта можно создать через ее клонирование.

$instance = new SimpleClass ();

$assigned = $instance ;
$reference =& $instance ;

$instance -> var = '$assigned будет иметь это значение' ;

$instance = null ; // $instance и $reference становятся null

var_dump ( $instance );
var_dump ( $reference );
var_dump ( $assigned );
?>

Результат выполнения данного примера:

В PHP 5.3.0 введены несколько новых методов создания экземпляров объекта:

class Test
static public function getNew ()
return new static;
>
>

class Child extends Test
<>

$obj1 = new Test ();
$obj2 = new $obj1 ;
var_dump ( $obj1 !== $obj2 );

$obj3 = Test :: getNew ();
var_dump ( $obj3 instanceof Test );

$obj4 = Child :: getNew ();
var_dump ( $obj4 instanceof Child );
?>

Результат выполнения данного примера:

extends

Класс может наследовать методы и свойства другого класса используя ключевое слово extends при его описании. Невозможно наследовать несколько классов, один класс может наследовать только один базовый класс.

Наследуемые методы и свойства могут быть переопределены (за исключением случаев, когда метод класса объявлен как final) путем объявления их с теми же именами, как и в родительском классе. Существует возможность доступа к переопределенным методам или статическим методам путем обращения к ним через parent::

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

class ExtendClass extends SimpleClass
// Переопределение метода родителя
function displayVar ()
echo "Расширенный класс\n" ;
parent :: displayVar ();
>
>

$extended = new ExtendClass ();
$extended -> displayVar ();
?>

Результат выполнения данного примера:

::class

Начиная с версии PHP 5.5 можно использовать ключевое слово class для разрешения имени класса. С помощью конструкции ClassName::class можно получить строку с абсолютным именем класса ClassName. Обычно это довольно полезно при работе с классами, использующими пространства имен.

This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

  • Open with Desktop
  • View raw
  • Copy raw contents Copy raw contents

Copy raw contents

Copy raw contents

15. Объектно-ориентированное программирование

15.1. Классы и объекты. Поля и методы

Класс — в объектно-ориентированном программировании, представляет собой шаблон для создания объектов, обеспечивающий начальные значения состояний: инициализация полей-переменных и реализация поведения функций или методов.

Объект - это экземпляр класса.

В PHP каждое определение класса начинается с ключевого слова class, затем следует имя класса, и далее пара фигурных скобок, которые заключают в себе определение свойств и методов этого класса.

Именем класса может быть любое слово, при условии, что оно не входит в список зарезервированных слов PHP, начинается с буквы или символа подчёркивания и за которым следует любое количество букв, цифр или символов подчёркивания.

15.2. Области видимости

Для полей и методов можно задавать области видимости

  • public — свойства или методы, объявленные как public, могут быть доступны в любом месте.
  • protected — protected свойства и методы доступны внутри класса, а также в дочерних классах.
  • private — доступ к private свойствам и методам имеет только класс, в котором эти свойства или методы объявлены

15.3. Переменная $this

Для того, чтобы обратиться к свойству или методу класса внутри другого метода этого класса, вместо имени объекта следует писать специальную переменную $this.

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

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

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

Конструкторы, определённые в классах-родителях не вызываются автоматически, если дочерний класс определяет собственный конструктор. Чтобы вызвать конструктор, объявленный в родительском классе, требуется вызвать parent::__construct() внутри конструктора дочернего класса. Если в дочернем классе не определён конструктор, то он может быть унаследован от родительского класса как обычный метод (если он не был определён как приватный).

Приватный конструктор. Паттерн Singleton

Singleton – один из самых простых шаблонов для понимания. Основное назначение – гарантировать существование только одно экземпляра класса. Причиной обычно является следующее: требуется только один объект исходного класса и Вам необходимо, что бы объект был доступен в любом месте приложения, т.е. глобальный доступ.

Для того, чтобы не дать возможность программисту создать несколько экземпляров класса, мы делаем конструктор приватным и в статическом поле храним единственный экземпляр класса

15.5. Динамический вызов свойств и методов

15.6. Статические свойства и методы. Константы

При работе с классами можно делать методы, которые для своего вызова не требуют создания объекта. Такие методы называются статическими.

Чтобы объявить метод статическим, нужно после модификатора доступа (то есть после public, private или protected) написать ключевое слово static.

Статические свойства принадлежат не какому-то объекту класса, а самому классу, хотя объекты класса и имеют доступ к этим свойствам. Внутри статических методов нельзя использовать $this .

15.7. Магические методы

Метод __set() будет выполнен при записи данных в недоступные (защищённые или приватные) или несуществующие свойства.

Метод __get() будет выполнен при чтении данных из недоступных (защищённых или приватных) или несуществующих свойств.

Метод __call() запускается при вызове недоступных методов в контексте объект.

Метод __toString() позволяет классу решать, как он должен реагировать при преобразовании в строку. Например, что вывести при выполнении echo $obj; .

Полный список магических методов: __construct(), __destruct(), __call(), __callStatic(), __get(), __set(), __isset(), __unset(), __sleep(), __wakeup(), __serialize(), __unserialize(), __toString(), __invoke(), __set_state(), __clone() и __debugInfo()

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

Например, мы хотим устанавливать возраст студента только если он больше 16 лет. Для этого мы можем переопределить родительский метод

Перезапись конструктора родительского класса

15.9. Наследование vs композиция и аггрегация

Наследование, композиция и агрегация - это способы взаимодействия классов между собой. Т.е. как один класс может использовать методы другого класса.

Это один из принципов ООП, который подразумевает, что класс наследник, будет иметь все те же свойства и методы, что и в базовом классе. В коде это выглядит так:

Один класс использует внутри своей реализации свойства или методы объекта другого класса. При этом используемый объект создается внутри класса. Пример:

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

У такого подхода есть один недостаток - сильная связанность, это значит, что, для того чтобы поменять класс A на A1, вам придется переписывать конструктор (new A1 вместо A).

Преимущество у такого способа, это то, что класс B, управляет временем жизни объекта A. Т.е. при удалении объекта B будет и удален, объект A который был создан внутри B.

Один класс использует внутри своей реализации свойства или методы объекта другого класса. При этом используемый объект создается вне класса. Пример:

В отличие от композиции, тут все наоборот. Преимущество: легко передать новый объект A1 без изменений в коде - слабая связанность. Из недостатков, пожалуй, следует отметить, что в больших системах это приводит к огромному кол-ву переменных в конструкторе

Композиция лучше наследования

Как говорится в известной книге "Шаблоны проектирования" Банды четырёх, по мере возможности нужно выбирать композицию, а не наследование. Есть много хороших причин использовать как наследование, так и композицию. Главная цель этой максимы заключается в том, если вы инстинктивно склоняетесь к наследованию, то постарайтесь представить, может ли композиция лучше решить вашу задачу. В каких-то случаях это действительно более подходящий вариант.

Вы спросите: "А когда лучше выбирать наследование?" Всё зависит от конкретной задачи, но можно ориентироваться на этот список ситуаций, когда наследование предпочтительнее композиции:

  • Ваше наследование — это взаимосвязь is-a, а не has-a. Пример: Человек → Животное vs. Пользователь → Детали пользователя (UserDetails).
  • Вы можете повторно использовать код из базовых классов. (Люди могут двигаться, как животные.)
  • Вы хотите внести глобальные изменения в производные классы, изменив базовый класс. (Изменение расхода калорий у животных во время движения.)

15.11. Трейты вместо множественного наследования

В PHP нельзя наследовать от нескольких классов сразу, только от одного.

Чтобы обойти это ограничение, вы можете использовать композицию. Однако в PHP есть и другой способ. Он заключается в использовании трейтов.

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

Синтаксис трейта такой же как и у класса, за исключением того, что имя трейта нужно объявлять с помощью ключевого слова trait.

Экземпляр трейта нельзя создать - трейты предназначены только для подключения к другим классам.

15.12. Абстрактные классы и интерфейсы. Полиморфизм

Абстрактные классы представляют собой классы, предназначенные для наследования от них. При этом объекты таких классов нельзя создать.

Пусть у вас есть класс User, а от него наследуют классы Employee и Student.

При этом предполагается, что вы будете создавать объекты классов Employee и Student, но объекты класса User - не будете, так как сам класс User используется только для группировки общих свойств и методов своих наследников.

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

Для того, чтобы объявить класс абстрактным, нужно при его объявлении написать ключевое слово abstract

Абстрактные классы также могут содержать абстрактные методы.

Такие методы не должны иметь реализации, а нужны для того, чтобы указать, что такие методы должны быть у потомков.

А собственно реализация таких методов - уже задача потомков.

Для того, чтобы объявить метод абстрактным, при его объявлении следует написать ключевое слово abstract.

При наследовании от абстрактного класса, все методы, помеченные абстрактными в родительском классе, должны быть определены в дочернем классе.

При этом область видимости этих методов должна совпадать или быть менее строгой. Что значит менее строгой: например, если абстрактный метод объявлен как protected, то реализация этого метода должна быть protected или public, но не private.

Объявления методов также должны совпадать: количество обязательных параметром должно быть одинаковым. Однако класс-потомок может добавлять необязательные параметры, которые не были указаны при объявлении метода в родителе.

Представим себе ситуацию, когда ваш абстрактный класс представляет собой только набор абстрактных публичных методов, не добавляя методы с реализацией.

Фактически ваш родительский класс описывает интерфейс потомков, то есть набор их публичных методов, обязательных для реализации.

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

Интерфейсы, так же, как и классы, могут наследовать друг от друга с помощью оператора extends. Каждый класс может реализовывать любое количество интерфейсов. Для этого имена интерфейсов нужно перечислить через запятую после ключевого слова implements.

В PHP пространства имён используются для решения двух проблем, с которыми сталкиваются авторы библиотек и приложений при создании повторно используемых элементов кода, таких как классы и функции:

  • Конфликт имён между вашим кодом и внутренними классами/функциями/константами PHP или сторонними.
  • Возможность создавать псевдонимы (или сокращения) для Ну_Очень_Длинных_Имён, чтобы облегчить первую проблему и улучшить читаемость исходного кода.

Пространства имён PHP предоставляют возможность группировать логически связанные классы, интерфейсы, функции и константы.

Для класса Page из файла /admin/page.php укажем пространство имен Admin:

А для класса Page из файла файл /users/page.php укажем пространство имен Users:

Давайте теперь в файле /index.php создадим объект одного и второго класса Page:

Конструкция use позволяет подключить класс по его полному имени, и после этого можно будет обращаться к этому классу просто по имени класса. Можно использовать псевдонимы для классов с помощью конструкции as . Это полезно, если вы хотите использовать классы с одинаковыми именами из разных неймспейсов

15.14. Автозагрузка через spl_autoload_register

Большинство разработчиков объектно-ориентированных приложений используют такое соглашение именования файлов, в котором каждый класс хранится в отдельно созданном для него файле. Одна из самых больших неприятностей - необходимость писать в начале каждого скрипта длинный список подгружаемых файлов (по одному для каждого класса).

Composer - это менеджер зависимостей для PHP. Вы можете описать от каких библиотек зависит ваш проект и Composer установит нужные библиотеки за вас.

При установке php пакетов Composer не просто устанавливает их, он также устанавливает все зависимости, от которых эти пакеты зависят. Т.е., например, если загружаемая библиотека будет зависеть от 3 других пакетов, а каждая из них, ещё в свою очередь от нескольких, то Composer всё это установит автоматически.

Загрузку сторонних библиотек Composer выполняет в папку vendor , которую данный php скрипт создаёт в корневой директории проекта. Также composer создаёт специальный файл autoload.php . Если вы подключите этот файл в проекте, вы сразу сможете использовать все загруженные библиотеки.

Пример: вызываем в консоли команду composer require monolog/monolog

Появятся файлы composer.json , composer.lock и папка vendor .

Файл composer.json - это главный файл Composer. В нем содержится описание основных пакетов, включая требования к их версиям.

Файл composer.lock - это файл, содержащий уже не требования, а реальные версии пакетов, которые были установлены на компьютер пользователя. Основное назначение файла composer.lock заключается в полном сохранении среды, в которой осуществлялась разработка и тестирование проекта. Например, если вы захотите скопировать проект в какое-то другое место без переноса файла composer.lock , то выполнив в нём команду composer install , вы можете получить другие версии пакетов. Это может случиться из-за выхода новых версий основных пакетов, описанных в файле composer.json , их зависимостей, зависимостей их зависимостей и т.д.

Если же вы разворачиваете проект, включающий в себя composer.lock , то вы получите те же версии зависимостей, которые были при разработке и тестировании. Поэтому composer.lock необходимо добавлять в git.

В папке vendor располагаются исходники библиотек и файл autoload.php . Вы можете подключить autoload.php и начать использовать классы, которые эти библиотеки предоставляют:

15.16. Автозагрузка собственных классов с помощью composer. Стандарт PSR-4

Вы даже можете добавить свой код в автозагрузчик, добавив поле autoload в composer.json

После добавления поля autoload в composer.json необходимо повторно выполнить команду dump-autoload для повторной генерации файла vendor/autoload.php

Composer зарегистрирует автозагрузчик PSR-4 для пространства имен App .

В таблице ниже представлены примеры соответствий полностью определённого имени класса, префикса пространства имён, базового каталога и итогового пути к файлу.

Fully Qualified Class Name Namespace Prefix Base Directory Resulting File Path
\Acme\Log\Writer\File_Writer Acme\Log\Writer ./acme-log-writer/lib/ ./acme-log-writer/lib/File_Writer.php
\Aura\Web\Response\Status Aura\Web /path/to/aura-web/src/ /path/to/aura-web/src/Response/Status.php
\Symfony\Core\Request Symfony\Core ./vendor/Symfony/Core/ ./vendor/Symfony/Core/Request.php
\Zend\Acl Zend /usr/includes/Zend/ /usr/includes/Zend/Acl.php

15.17 Reflection API

Рефлексия (отражение) - процесс, во время которого программа может отслеживать и модифицировать собственную структуру и поведение во время выполнения. PHP включает в себя полноценный Reflection API, который предоставляет возможность проводить интроспекцию классов, интерфейсов, функций, методов и модулей. Кроме того, Reflection API позволяет получать doc-блоки комментариев функций, классов и методов.

Класс Profile является черным ящиком. И если у нас нет доступа к коду, то посмотреть как он устроен можно используя ReflectionClass:

ReflectionClass похож на аналитика для класса Profile, и это основная идея Reflection API.

PHP дает ключи к закрытым параметрам, поэтому мы можем получить доступ к ним с помощью:

ReflectionClass: сообщает информацию о классе. ReflectionFunction: сообщает информацию о функции. ReflectionParameter: извлекает информацию о параметрах функции или метода. ReflectionClassConstant: сообщает информацию о константе класса.

Reflection API входит в состав языка, поэтому нет необходимости в дополнительной установке или конфигурации.

Механизм рефлексии широко используется генераторами документаций, а так же в фреймворках для конфигурирования роутингов, параметров сериализации, настройки прав доступа и т.д.

15.18 SPL - Standart PHP Library

Стандартная библиотека PHP (SPL) - это набор интерфейсов и классов, предназначенных для решения стандартных задач.

SPL предоставляет ряд стандартных структур данных, итераторов для итерирования объектов, интерфейсов, стандартных исключений, некоторое количество классов для работы с файлами и предоставляет ряд функций, например spl_autoload_register().

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

Читайте также: