Что такое объект в php
Перейти к содержимому

Что такое объект в php

  • автор:

Объекты и классы в PHP

Объекты в PHP — это просто ещё один тип данных. Объект позволяет хранить в переменной набор из свойств и их значений, а также встроенные функции. Это делает объекты похожими по своей структуре на ассоциативные массивы. Но отличие от массивов всё-таки есть, и при этом достаточно важное — объекты могут иметь внутреннее состояние.

Особенности объектов и их отличия от массивов

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

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

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

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

Анатомия объекта

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

Вторая группа — это методы объекта.

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

Классы

Класс — это шаблон, по которому создаются объекты.

Невозможно создать объект «на лету», как это происходит с массивами. Объект создаётся только на основе своего описания — класса. Этим реализация объектов в PHP отличается от JavaScript. В JS объектам не нужны классы, они могут быть созданы и модифицированы когда и как угодно.

Класс как чертёж

Зачем нужны классы, и почему объекты не могут существовать без них?

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

Жизненный цикл объекта

✅ Любая работа с объектами в PHP состоит из следующих этапов.

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

Пример создания объекта на основе класса

class WeatherEntry < private $date; private $comment = ""; private $temperature = 0; private $isRainy = false; public function __construct($date, string $comment, int $temperature) < $this->date = $date; $this->comment = $comment; $this->temperature = $temperature; > public function isCold() < return $this->temperature < 0; >public function setRainStatus($rain_status) < $this->isRainy = $rain_status; > public function getDayDescription() < $dt = strtotime($this->date); $delta = time() - $dt; $days = ceil($delta / 86400); $res = "Это было $days дней назад. В тот день было"; if ($this->isCold()) < $res .= "холодно. "; >else < $res .= "довольно тепло."; >if ($this->isRainy) < $res .= "Семенил дождь."; >else < $res .= "На небе не было ни облачка."; >return $res; > > 

Создание объекта на основе класса:

$firstSeptember = new WeatherEntry("2018-09-01", "День знаний", 14); $firstSeptember->setRainStatus(false); print($firstSeptember->getDayDescription()); 

Разбор примера

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

В классе определено четыре скрытых свойства. Это значит, что к ним не будет доступа за пределами объекта. Читать и записывать эти свойства могут только внутренние методы объекта. Сами свойства хранят температурные параметры (температуру, осадки), дату и дополнительный комментарий к записи. Некоторым свойствам задано значение по умолчанию.

Далее идёт перечисление методов. И начинается всё с метода, у которого особое имя и значение — __construct .

Что такое конструктор объекта

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

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

Обращение к свойствам и методам объекта

Посмотрим, как внутри метода происходит обращение к свойствам.

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

Во-вторых, для обращения к методам и свойствам объекта нужен специальный синтаксис: «стрелочка». Такая стрелочка отделяет имя свойства или метода от имени объекта. Это аналог квадратных скобок при работе с массивами.

Метод с именем isCold() нужен, чтобы узнать, было ли холодно в тот день, основываясь на показаниях температуры в градусах.

Метод setRainStatus() устанавливает логическое значение, которое показывает статус осадков в день наблюдения.

Метод getDayDescription() формирует текстовое описание погоды на заданную дату.

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

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

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

В коде передаём в конструктор почти все параметры погодных наблюдений. Затем для созданного объекта вызываются его методы: первый устанавливает значения осадков, а второй возвращает текстовое описание погоды.

«Доктайп» — журнал о фронтенде. Читайте, слушайте и учитесь с нами.

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

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

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

Для создания класса в PHP используется ключевое слово class , после которого идет название класса и фигурные скобки <> — блок кода класса. Например, новый класс, представляющий пользователя:

class Person <>

Чтобы создать объект класса Person, применяется ключевое слово new :

 $person = new Person(); print_r($person); ?>

В данном случае переменная $person является объектом класса Person . С помощью функции print_r() можно вывести содержимое объекта, как и в случае с массивами.

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

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

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

Так, добавим в класс Person несколько свойств и методов:

"; > > $tom = new Person(); $tom->name = "Tom"; // установка свойства $name $tom->age = 36; // установка свойства $age $personName = $tom->name; // получение значения свойства $name echo "Имя пользователя: " . $personName . "
"; $tom->hello(); // вызов метода hello() print_r($tom); ?>

Здесь класс Person содержит два свойства: $name и $age . Свойства объявляются как обычные переменные, перед которыми стоит модификатор доступа — в данном случае модификатор public .

Методы представляют обычные функции, которые выполняют определенные действия. Здесь функция hello() просто выводит приветствие.

После создания объекта класса Person:

$tom = new Person();

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

$tom->name = "Tom"; // установка свойства $name $tom->age = 36; // установка свойства $age

Или получить значение (например, присвоить его переменной):

$personName = $tom->name; // получение значения свойства $name

Или вызвать методы объекта:

$tom->hello(); // вызов метода hello()

В итоге мы получим следующий вывод браузера:

Имя пользователя: Tom Hello! Person Object ( [name] => Tom [age] => 36 )

При этом свойствам можно задать в классе некоторые начальные значения:

"; > > $tom = new Person(); $tom->age = 36; // установка свойства $age echo "Имя пользователя: " . $tom->name . "
"; echo "Возраст пользователя: " . $tom->age . "
"; ?>
Имя пользователя: Undefined Возраст пользователя: 36

Ключевое слово this

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

name ."; Age: " . $this->age . "
"; // также можно написать // echo "Name: $this->name; Age: $this->age
"; > > $tom = new Person(); $tom -> name = "Tom"; $tom -> displayInfo(); // Name: Tom; Age: 18 ?>

Для обращения к полям и методам внутри класса также применяется оператор доступа -> , перед которым идет $this . Причем это $this указывает именно на текущий объект. Что это значит в практическом плане? Например:

name; Age: $this->age
"; > > $tom = new Person(); $tom -> name = "Tom"; $tom -> displayInfo(); $bob = new Person(); $bob -> name = "Bob"; $bob -> age = 25; $bob -> displayInfo(); ?>
$tom -> displayInfo();

$this фактически будет указывать на переменную $tom . Тогда как при вызове

$bob -> displayInfo();

$this будет указывать на переменную $bob .

Name: Tom; Age: 18 Name: Bob; Age: 25

Сравнение объектов

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

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

Рассмотрим на примере:

name; Age: $this->age
"; > > $tom = new Person(); $tom -> name = "Tom"; $tom -> age = 36; $tomas = new Person(); $tomas -> name = "Tom"; $tomas -> age = 36; if($tom == $tomas) echo "переменные tom и tomas равны
"; else echo "переменные tom и tomas НЕ равны
"; if($tom === $tomas) echo "переменные tom и tomas эквивалентны"; else echo "переменные tom и tomas НЕ эквивалентны"; ?>

Здесь сравниваются две переменных — $tom и $tomas. Они представляют один и тот же класс Person, и их свойства имеют одни и те же значения. Однако они представляют разные объекты. Поэтому при сравнении оператор == возвратит true , а оператор === — false :

переменные tom и tomas равны переменные tom и tomas НЕ эквивалентны

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

$person = new Person(); $tom = $person; $tom -> name = "Tom"; $tom -> age = 36; $tomas = $person; if($tom == $tomas) echo "переменные tom и tomas равны
"; else echo "переменные tom и tomas НЕ равны
"; if($tom === $tomas) echo "переменные tom и tomas эквивалентны"; else echo "переменные tom и tomas НЕ эквивалентны";

Здесь объект класса Person создается только один раз: $person = new Person(); . И затем обе переменных $tom и $tomas будут указывать на этот объект. При этом не имеет значения, для какой именно переменной мы устанавливаем свойства. Так как в реальности это будет один и тот же объект. В итоге и оператор == , и оператор === при сравнении возвратят true

переменные tom и tomas равны переменные tom и tomas эквивалентны

Что такое объект в php

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

$bar = new foo ;
$bar -> do_foo ();
?>

Полное рассмотрение производится в разделе Классы и Объекты.

Преобразование в объект

Если object преобразовывается в object , объект не изменится. Если значение другого типа преобразовывается в object , создаётся новый экземпляр встроенного класса stdClass . Если значение было null , новый экземпляр будет пустым. Массивы преобразуются в object с именами полей, названными согласно ключам массива и соответствующими им значениям. Обратите внимание, что в этом случае до PHP 7.2.0 числовые ключи не будут доступны, пока не проитерировать объект.

$obj = (object) array( ‘1’ => ‘foo’ );
var_dump (isset( $obj ->< '1' >)); // выводит ‘bool(true)’, начиная с PHP 7.2.0; ‘bool(false)’ ранее
var_dump ( key ( $obj )); // выводит ‘string(1) «1»‘, начиная с PHP 7.2.0; ‘int(1)’ ранее
?>

При преобразовании любого другого значения, оно будет помещено в поле с именем scalar соответствующему типу.

$obj = (object) ‘привет’ ;
echo $obj -> scalar ; // выведет ‘привет’
?>

User Contributed Notes 8 notes

12 years ago

By far the easiest and correct way to instantiate an empty generic php object that you can then modify for whatever purpose you choose:

I had the most difficult time finding this, hopefully it will help someone else!

8 years ago

In PHP 7 there are a few ways to create an empty object:

$obj1 = new \stdClass ; // Instantiate stdClass object
$obj2 = new class<>; // Instantiate anonymous class
$obj3 = (object)[]; // Cast empty array to object

var_dump ( $obj1 ); // object(stdClass)#1 (0) <>
var_dump ( $obj2 ); // object(class@anonymous)#2 (0) <>
var_dump ( $obj3 ); // object(stdClass)#3 (0) <>
?>

$obj1 and $obj3 are the same type, but $obj1 !== $obj3. Also, all three will json_encode() to a simple JS object <>:

8 years ago

As of PHP 5.4, we can create stdClass objects with some properties and values using the more beautiful form:

$object = (object) [
‘propertyOne’ => ‘foo’ ,
‘propertyTwo’ => 42 ,
];
?>

7 years ago

echo «» ;
print_r ( $obj ); //stdClass Object created by casting of array

$newobj = new stdClass (); //create a new
$newobj -> name = «India» ;
$newobj -> work = «Development» ;
$newobj -> address = «patna» ;

$new = (array) $newobj ; //convert stdClass to array
echo «» ;
print_r ( $new ); //print new object

##How deals with Associative Array

$test = [ Details =>[ ‘name’ , ‘roll number’ , ‘college’ , ‘mobile’ ], values =>[ ‘Naman Kumar’ , ‘100790310868’ , ‘Pune college’ , ‘9988707202’ ]];
$val = json_decode ( json_encode ( $test ), false ); //convert array into stdClass object

echo «» ;
print_r ( $val );

echo (( is_array ( $val ) == true ? 1 : 0 ) == 1 ? «array» : «not an array» ). «
» ; // check whether it is array or not
echo (( is_object ( $val ) == true ? 1 : 0 ) == 1 ? «object» : «not an object» ); //check whether it is object or not
?>

9 years ago

Here a new updated version of ‘stdObject’ class. It’s very useful when extends to controller on MVC design pattern, user can create it’s own class.

Hope it help you.

class stdObject public function __construct (array $arguments = array()) if (!empty( $arguments )) foreach ( $arguments as $property => $argument ) $this -> < $property >= $argument ;
>
>
>

public function __call ( $method , $arguments ) $arguments = array_merge (array( «stdObject» => $this ), $arguments ); // Note: method argument 0 will always referred to the main class ($this).
if (isset( $this ->< $method >) && is_callable ( $this ->< $method >)) return call_user_func_array ( $this ->< $method >, $arguments );
> else throw new Exception ( «Fatal error: Call to undefined method stdObject:: < $method >()» );
>
>
>

$obj = new stdObject ();
$obj -> name = «Nick» ;
$obj -> surname = «Doe» ;
$obj -> age = 20 ;
$obj -> adresse = null ;

$obj -> getInfo = function( $stdObject ) < // $stdObject referred to this object (stdObject).
echo $stdObject -> name . » » . $stdObject -> surname . » have » . $stdObject -> age . » yrs old. And live in » . $stdObject -> adresse ;
>;

$obj -> setAge ( 24 ); // Parameter value 24 is passing to the $age argument in method ‘setAge()’.

// Create dynamic method. Here i’m generating getter and setter dynimically
// Beware: Method name are case sensitive.
foreach ( $obj as $func_name => $value ) if (! $value instanceOf Closure )

$obj -> setName ( «John» );
$obj -> setAdresse ( «Boston» );

Что такое объект в php

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

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

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

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

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

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

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

Внимание

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

Пример #2 Некоторые примеры псевдо-переменной $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:

$this определена (A) Deprecated: Non-static method A::foo() should not be called statically in %s on line 27 $this не определена. Deprecated: Non-static method A::foo() should not be called statically in %s on line 20 $this не определена. Deprecated: Non-static method B::bar() should not be called statically in %s on line 32 Deprecated: Non-static method A::foo() should not be called statically in %s on line 20 $this не определена.

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

$this определена (A) Fatal error: Uncaught Error: Non-static method A::foo() cannot be called statically in %s :27 Stack trace: #0 thrown in %s on line 27
Классы, доступные только для чтения

Начиная с PHP 8.2.0, класс может быть помечен модификатором readonly . Пометка класса как readonly добавит модификатор readonly к каждому объявленному свойству и предотвратит создание динамических свойств. Более того, невозможно добавить их поддержку с помощью атрибута AllowDynamicProperties . Попытка это сделать приведёт к ошибке компиляции.

#[ \AllowDynamicProperties ]
readonly class Foo >

// Fatal error: Cannot apply #[AllowDynamicProperties] to readonly class Foo
?>

Поскольку ни нетипизированные, ни статические свойства не могут быть помечены модификатором readonly , классы, доступные только для чтения также не могут их объявлять:

// Fatal error: Readonly property Foo::$bar must have type
?>

readonly class Foo
public static int $bar ;
>

// Fatal error: Readonly class Foo cannot declare static properties
?>

Класс readonly может быть расширен тогда и только тогда, когда дочерний класс также является классом readonly .

new

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

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

Замечание:

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

Пример #3 Создание экземпляра класса

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

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

Пример #4 Создание экземпляра с использованием произвольного выражения

В данном примере мы показываем несколько вариантов допустимых произвольных выражений, которые представляют имя класса. Пример вызова функции, конкатенации строк и константы ::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:

object(ClassA)#1 (0) < >object(ClassB)#1 (0) < >object(ClassC)#1 (0) < >object(ClassD)#1 (0)

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

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

Пример #5 Присваивание объекта

$instance = new SimpleClass ();

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

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

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

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

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

NULL NULL object(SimpleClass)#1 (1) < ["var"]=>string(30) "$assigned будет иметь это значение" >

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

Пример #6 Создание новых объектов

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 );
?>

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

bool(true) bool(true) bool(true)

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

Пример #7 Доступ к свойствам/методам только что созданного объекта

echo (new DateTime ())-> format ( ‘Y’ );
?>

Вывод приведённого примера будет похож на:

2016

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

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

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

Пример #8 Доступ к свойству vs. вызов метода

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

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

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

свойство метод

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

Пример #9 Вызов анонимной функции, содержащейся в свойстве

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

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

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

extends

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

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

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

Пример #10 Простое наследование классов

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

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

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

Расширенный класс значение по умолчанию
Правила совместимости сигнатуры

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

Пример #11 Совместимость дочерних методов

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 );

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

Допустимо Допустимо

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

Пример #12 Фатальная ошибка, когда дочерний метод удаляет параметр

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

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

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

Fatal error: Declaration of Extend::foo() must be compatible with Base::foo(int $a = 5) in /in/evtlq on line 13

Пример #13 Фатальная ошибка, когда дочерний метод делает необязательный параметр обязательным.

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

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

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

Fatal error: Declaration of Extend::foo(int $a) must be compatible with Base::foo(int $a = 5) in /in/qJXVC on line 13

Внимание

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

Пример #14 Ошибка при использовании именованных аргументов и параметров, переименованных в дочернем классе

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

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

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

Вывод приведённого примера будет похож на:

Fatal error: Uncaught Error: Unknown named parameter $foo in /in/XaaeN:14 Stack trace: #0 thrown in /in/XaaeN on line 14

::class

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

Пример #15 Разрешение имени класса

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

NS\ClassName

Замечание:

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

Пример #16 Отсутствует разрешение имени класса

print Does\Not\Exist ::class;
?>

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

Does\Not\Exist

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

Пример #17 Разрешение имени объекта

namespace NS class ClassName >
>
$c = new ClassName ();
print $c ::class;
?>

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

NS\ClassName

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

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

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

Пример #18 Оператор Nullsafe

// Начиная с 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 11 notes

16 years ago

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 );

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *