Объекты и классы в 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)’ ранее
?>?php
При преобразовании любого другого значения, оно будет помещено в поле с именем scalar соответствующему типу.
$obj = (object) ‘привет’ ;
echo $obj -> scalar ; // выведет ‘привет’
?>?php
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: Объектно-ориентированный дизайн
Чаще всего когда говорят про ООП, то рассуждают про сущности предметной области, например пользователи, заказы, товары и тому подобное. У такого использования объектов есть определенные условия, которые должны соблюдаться для обеспечения нормального функционирования.
Стоит сказать, что подобное использование ООП, хоть и описывается во всех учебниках как пример нужности ООП, имеет слабое отношение к реальному коду. На практике, большинство существующих классов и объектов в коде приложений, библиотек и фреймворков не имеют никакой связи с предметной областью. Их появление и использование крутится вокруг такой темы как полиморфизм, которая изучается в соответствующем курсе.
Время жизни. Подобные объекты создаются не ради одноразового использования, а живут какое-то время во время запуска программы или, что чаще, между запусками в каком-то хранилище. Например, пользователи на Хекслете представлены объектами класса User. Они создаются во время регистрации и потом существуют в системе бесконечное время. Изредка они удаляются по инициативе самих пользователей.
Идентификация. Каким образом один пользователь отличается от другого? На первый взгляд, кажется, что можно использовать имя и фамилию. Но если разобраться, то никакой набор параметров не даст 100% надежности с одной стороны, а с другой они все могут измениться и точно изменятся со временем. Поэтому при работе с сущностями вводят искусственные идентификаторы, которые, как правило, формирует база данных. Затем сравнение происходит именно по ним.
class User public function __construct($id, $name) $this->id = $id; $this->name = $name; > public function equals($user) return $this->id === $user->id; > > // С точки зрения нашей системы это один и тот же пользователь // С точки зрения PHP – разные объекты $user1 = new User(3, 'mike'); $user2 = new User(3, 'mike'); $user3 = new User(1, 'mike'); // Подобная схема проверки существует во всех ORM $user1->equals($user2); // true $user1->equals($user3); // false
Это очень напоминает механизм строгого сравнения объектов в PHP. Они сравниваются не по совпадению данных, а по ссылке, которая внутри представлена каким-то числовым значением. Поэтому разные объекты хранящие одинаковые данные это всегда разные объекты, что логично.
Объекты имеющие свою идентификацию и время жизни называют объектами-сущностями (entities), но кроме них существует и другая разновидность объектов, тоже, как правило, связанная с предметной областью – это объекты-значения. Что это?
Объекты-Значения (value objects)
Когда у нас в кошельке лежит 10$, то нам не важно какая конкретно это купюра. Мы легко можем взять эту купюру, поменять ее на другую эквивалентную по номиналу. Для нас в этот момент ничего не меняется. Десять долларов остались десятью долларами. То же самое можно сказать и про многое другое, например: адреса доставки, страна проживания, путь до файла, адрес страницы сайта, точки на плоскости. Во всех этих ситуациях нас волнует само значение, сам факт его существования.
Представьте себе систему в которой идет работа с деньгами. Причем в разных валютах. В такой ситуации удобно представить деньги в виде объекта, который помимо номинала хранит информацию о валюте. Как в таком случае должно работать сравнение?
$m1 = new Money(150, 'usd'); $m2 = new Money(130, 'eur'); // Предположим что 150 долларов по текущему курсу равны 130 евро // Функция конвертирует деньги для сравнения $m1->equals($m2); // true
Данный код выражает озвученную ранее идею. Нам не важны объекты, нам важны значения. Объект здесь служит лишь способом организации кода, но он никак не идентифицирует хранящиеся внутри него данные. Такие объекты называют объектами-значениями .
Если говорить откровенно, то реальность чуть сложнее. Одни и те же вещи могут быть как объектами-значениями так и объектами-сущностями. Всё зависит от конкретной предметной области. Для большинства компаний деньги — это действительно просто значения, но не для тех кто их печатает. Им очень важно различать купюры между собой и поэтому на каждой из них есть уникальный номер, который и позволяет проводить идентификацию.
Объекты-значения – искусственная штука. Часто они не нужны и достаточно пользоваться простым значением, особенно если оно примитивное. С другой стороны, когда значение составное, такое как точка на плоскости, адрес или адрес страницы сайта (она состоит из многих частей), подобные объекты помогают упростить код за счет удобной абстракции.
Встраиваемые объекты (embedded objects)
Как правило, данные, с которыми работают веб-приложения, хранятся в реляционных базах данных. В них каждая сущность представляется строкой в таблице, где каждое поле соответствует свойству объекта. При такой организации хранения, иногда, возникают ситуации, когда часть свойств сущности описывают собой что-то одно. Распространенный пример – почтовый адрес:
// Поиск из базы по идентификатору // Гипотетический код $user = $users->find(5); $user->street; // 'lenina' $user->zipcode; // 432111 $user->house; // 10
Существует два подхода для работы с такими данными. Первый, любая логика по работе с этими данными описывается внутри самой сущности. Например вывод адреса в виде текста:
class User // Где-то здесь конструктор и другие методы public function getFullAddress() return "$this->street>, $this->house>, $this->zipcode>"; > > $user->getFullAddress();
Главная проблема здесь — возможное дублирование, если адрес встречается где-то еще, кроме пользователя. Тогда придется реализовывать методы по работе с этими данными везде, где они встречаются.
Второй подход – создать отдельный класс и внедрить объект этого класса в основной объект. Звучит страшно, но на практике очень просто:
class Address public function __construct($street, $house, $zipcode) $this->street = $street; $this->house = $house; $this->zipcode = $zipcode; > public function toString() return "$this->street>, $this->house>, $this->zipcode>"; > > class User // Где-то здесь конструктор и другие методы public function getAddress() // Так как у нас объект-значение, // то можно, не боясь, создавать его любое количество раз, // но в случае необходимости можно этот процесс оптимизировать return new Address($this->street, $this->house, $this->zipcode); > >
Открыть доступ
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
- 130 курсов, 2000+ часов теории
- 1000 практических заданий в браузере
- 360 000 студентов
Наши выпускники работают в компаниях: