Php способы создания объекта

PHP: Классы и объекты

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

Определение класса

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

Класс first из приведенного примера — уже полноправный класс, хотя пока и не слишком полезный. Но тем не менее мы сделали нечто очень важное. Мы определили тип, т.е. создали категорию данных, которые мы можем использовать в своих сценариях. Важность этого станет для вас очевидной по мере дальнейшего чтения главы.

Создание объекта

Так как класс — это шаблон для создания объектов, следовательно, объект — это данные, которые создаются и структурируются в соответствии с шаблоном, определенным в классе. Объект также называют экземпляром класса, тип которого определяется классом. Для создания нового экземпляра класса нам понадобится оператор new . Он используется совместно с именем класса следующим образом:

После оператора new указывается имя класса на основе которого будет создан объект. Оператор new создает экземпляр класса и возвращает ссылку на вновь созданный объект. Эта ссылка сохраняется в переменной соответствующего типа. В результате выполнения этого кода будет создано два объект типа first . Хотя функционально они идентичны (т.е. пусты) $obj1 и $obj2 — это два разных объекта одного типа, созданных с помощью одного класса.

Если вам все еще не понятно, давайте приведем аналогию из реальной жизни. Представьте, что класс — это форма для отливки, с помощью которой изготавливаются пластмассовые машинки. Объекты — это и есть машинки. Тип создаваемых объектов определяется формой отливки. Машинки выглядят одинаковыми во всех отношениях, но все-таки это разные предметы. Другими словами, это разные экземпляры одного и того же типа.

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

Определение свойств

В классе можно определить переменные. Переменные, которые определены в классе называются свойствами (или полями данных). Они определяются с одним из ключевых слов protected, public или private , характеризующих управление доступом. Эти ключевые слова мы рассмотрим подробно в следующей главе. А сейчас давайте определим некоторые свойства с помощью ключевого слова public :

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

Примечание: значения инициализирующие свойства должны быть литералами (константными значениями), инициализировать свойства в классе не обязательно (если значение не указано, по умолчанию это будет NULL ).

К свойствам объекта можно обращаться с помощь символов ‘ -> ‘, указав объект и имя свойства. Поскольку свойства объектов были определены как public , мы можем считывать их значения, а также присваивать им новые значения, заменяя тем самым начальные значения, определенные в классе:

На самом деле в PHP необязательно объявлять все свойства в классе. Свойства можно добавлять к объекту динамически:

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

Работа с методами

Методы — это обычные функции, которые определяются внутри класса, они позволяют объектам выполнять различные задачи. Объявление метода напоминает определение обычной функции, за исключением предваряемого одного из ключевых слов protected, public или private . Если в определении метода вы опустите ключевое слово, определяющее видимость, то метод будет объявлен неявно как public . К методам объекта можно обращаться с помощь символов ‘ -> ‘, указав объект и имя метода. При вызове метода, так же как и при вызове функции нужно использовать круглые скобки.

Читайте также:  10 способов сделать детей счастливыми

Мы добавили метод getstr() к классу first . Обратите внимание на то, что при определении метода мы не использовали ключевое слово, определяющее область видимости. Это означает, что метод getstr() относится к типу public и его можно вызвать за пределами класса.

В определении метода мы воспользовались специальной псевдопеременной $this . Она используется для обращения к методам или свойствам внутри класса и имеет следующий синтаксис:

Значением переменной $this является ссылка на текущий объект. Чтобы стало понятнее посмотрите на следующий пример:

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

Специальный метод — конструктор

У класса может быть определен специальный метод — конструктор , который вызывается каждый раз при создании нового экземпляра класса (объекта) с целью инициализировать его, например установить значения свойств. Конструктор, как и любой другой метод может иметь параметры. Чтобы определить метод в качестве конструктора его необходимо назвать __construct() . Обратите внимание на то, что имя метода должно начинаться с двух символов подчеркивания. Посмотрим, как это работает:

Метод __construct вызывается, когда создается объект с помощью оператора new . Указанные в скобках аргументы передаются конструктору. В методе конструктора используется псевдопеременная $this для присвоения значений соответствующим свойствам создаваемого объекта.

Указание типа аргумента в методах

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

Теперь в качестве аргумента методу getobj() можно передавать только экземпляры типа cat . Поскольку метод getobj() содержит уточнение типа класса, передача ему объекта типа wrong приведет к ошибке.

Указание типа нельзя использовать для определения параметров элементарных типов, таких как строки, числа и т.д. Для этой цели в теле метода следует использовать функции проверки типов, например is_string() . Также есть возможность определить, что передаваемый аргумент является массивом:

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

Если вместо NULL указать какое-либо другое значение по умолчанию, будет выдана ошибка.

Источник

Php способы создания объекта

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

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

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

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

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

class OtherSubClass extends BaseClass <
// наследует конструктор BaseClass
>

// Конструктор класса BaseClass
$obj = new BaseClass ();

// Конструктор класса BaseClass
// Конструктор класса SubClass
$obj = new SubClass ();

// Конструктор класса BaseClass
$obj = new OtherSubClass ();
?>

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

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

Пример #2 Использование аргументов в конструкторах

class Point <
protected int $x ;
protected int $y ;

public function __construct ( int $x , int $y = 0 ) <
$this -> x = $x ;
$this -> y = $y ;
>
>

Читайте также:  Способ подачи жареной рыбы

// Передаём оба параметра.
$p1 = new Point ( 4 , 5 );
// Передаём только обязательные параметры. Для $y используется значеие по умолчанию 0.
$p2 = new Point ( 4 );
// Вызываем с именованными параметрами (начиная с PHP 8.0):
$p3 = new Point ( y : 5 , x : 4 );
?>

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

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

До PHP 8.0.0, классы в глобальном пространстве имён будут интерпретировать метод, названный так же, как класс, как конструктор старого стиля. Этот синтаксис считается устаревшим и будет вызывать ошибку уровня E_DEPRECATED , но всё равно эти методы будут вызываться в качестве конструктора. Если в классе присутствуют и __construct(), и метод с именем класса, то в качестве конструктора будет вызван __construct().

Для классов, находящихся в собственном пространстве имён и для всех классов, начиная с PHP 8.0.0, метод, названный по имени класса, будет игнорироваться.

В новом коде всегда используйте __construct().

Определение свойств объекта в конструкторе

Начиная с PHP 8.0.0, параметры конструктора можно использовать для задания соответствующих свойств объекта. Это довольно распространённая практика — присваивать свойствам объекта параметры, переданные в конструктор, не производя никаких дополнительных преобразований. Определение свойств класса в конструкторе позволяет значительно сократить количество шаблонного кода для такого случая. Пример выше можно будет переписать следующим образом:

Пример #3 Использование определения свойств в конструкторе

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

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

Свойства объектов не могут быть типа callable в связи с неоднозначностью которую они представляют для движка PHP. Соответственно и свойства определяемые в конструкторе также не могут быть типа callable . Любые другие декларации типов допустимы.

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

Статические методы создания объекта

PHP поддерживает только один конструктор для класса. Однако в некоторых случаях есть необходимость создавать объект разными путями в зависимости от разных входных данных. Рекомендуемый способ — использовать статические методы как обёртки над конструктором.

Пример #4 Использование статических методов для создания объектов

private ? int $id ;
private ? string $name ;

private function __construct (? int $id = null , ? string $name = null ) <
$this -> id = $id ;
$this -> name = $name ;
>

public static function fromBasicData ( int $id , string $name ): static <
$new = new static( $id , $name );
return $new ;
>

public static function fromJson ( string $json ): static <
$data = json_decode ( $json );
return new static( $data [ ‘id’ ], $data [ ‘name’ ]);
>

public static function fromXml ( string $xml ): static <
// Пользовательская логика.
$data = convert_xml_to_array ( $xml );
$new = new static();
$new -> id = $data [ ‘id’ ];
$new -> name = $data [ ‘name’ ];
return $new ;
>
>

$p1 = Product :: fromBasicData ( 5 , ‘Widget’ );
$p2 = Product :: fromJson ( $some_json_string );
$p3 = Product :: fromXml ( $some_xml_string );

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

В примере выше три публичных статических метода демонстрируют различные способы создания экземпляра объекта.

  • fromBasicData() принимает явные параметры, создаёт экземпляр класса через конструктор и возвращает объект.
  • fromJson() принимает JSON строку, производит над ней некоторые преобразования, извлекает данные необходимые для создания объекта и, так же как и предыдущий метод, вызывает конструктор и возвращает созданный объект.
  • fromXml() принимает XML строку, извлекает нужные данные и, так как в конструкторе нет обязательных параметров, вызывает его без них. После этого, так как ему доступны скрытые свойства, он присваивает им значения напрямую. После чего возвращает готовый объект.
Читайте также:  Как вылечить колени народный способ

Во всех трёх случаях, ключевое слово static транслируется в имя класса, в котором этот код вызывается. В нашем случае Product .

Деструкторы

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

Пример #5 Пример использования деструктора

class MyDestructableClass
<
function __construct () <
print «Конструктор\n» ;
>

function __destruct () <
print «Уничтожается » . __CLASS__ . «\n» ;
>
>

$obj = new MyDestructableClass ();

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

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

Деструкторы, вызываемые при завершении скрипта, вызываются после отправки HTTP-заголовков. Рабочая директория во время фазы завершения скрипта может отличаться в некоторых SAPI (например, в Apache).

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

User Contributed Notes 12 notes

Be aware of potential memory leaks caused by circular references within objects. The PHP manual states «[t]he destructor method will be called as soon as all references to a particular object are removed» and this is precisely true: if two objects reference each other (or even if one object has a field that points to itself as in $this->foo = $this) then this reference will prevent the destructor being called even when there are no other references to the object at all. The programmer can no longer access the objects, but they still stay in memory.

Consider the following example:

/**
* An indentifier
* @var string
*/
private $name ;
/**
* A reference to another Foo object
* @var Foo
*/
private $link ;

public function __construct ( $name ) <
$this -> name = $name ;
>

public function setLink ( Foo $link ) <
$this -> link = $link ;
>

public function __destruct () <
echo ‘Destroying: ‘ , $this -> name , PHP_EOL ;
>
>

// create two Foo objects:
$foo = new Foo ( ‘Foo 1’ );
$bar = new Foo ( ‘Foo 2’ );

// make them point to each other
$foo -> setLink ( $bar );
$bar -> setLink ( $foo );

// destroy the global references to them
$foo = null ;
$bar = null ;

// we now have no way to access Foo 1 or Foo 2, so they OUGHT to be __destruct()ed
// but they are not, so we get a memory leak as they are still in memory.
//
// Uncomment the next line to see the difference when explicitly calling the GC:
// gc_collect_cycles();
//
// see also: http://www.php.net/manual/en/features.gc.php
//

// create two more Foo objects, but DO NOT set their internal Foo references
// so nothing except the vars $foo and $bar point to them:
$foo = new Foo ( ‘Foo 3’ );
$bar = new Foo ( ‘Foo 4’ );

// destroy the global references to them
$foo = null ;
$bar = null ;

// we now have no way to access Foo 3 or Foo 4 and as there are no more references
// to them anywhere, their __destruct() methods are automatically called here,
// BEFORE the next line is executed:

echo ‘End of script’ , PHP_EOL ;

Destroying: Foo 3
Destroying: Foo 4
End of script
Destroying: Foo 1
Destroying: Foo 2

But if we uncomment the gc_collect_cycles(); function call in the middle of the script, we get:

Destroying: Foo 2
Destroying: Foo 1
Destroying: Foo 3
Destroying: Foo 4
End of script

As may be desired.

NOTE: calling gc_collect_cycles() does have a speed overhead, so only use it if you feel you need to.

Источник

Оцените статью
Разные способы