- Определение класса
- Создание объекта
- Определение свойств
- Работа с методами
- Специальный метод — конструктор
- Указание типа аргумента в методах
Поскольку именно классы описывают объекты, мы начнем описание с определения классов.
Определение класса
Класс — это шаблон кода, который используется для создания объектов. Класс определяется с помощью ключевого слова class после которого указывается произвольное имя класса. В имени класса может использоваться любое сочетание букв и цифр, но они не должны начинаться с цифры. Код, связанный с классом должен быть заключен в фигурные скобки, которые указываются после имени. Определение класса описывает, какие элементы будут содержаться в каждом новом экземпляре этого класса. На основе полученных данных давайте посмотрим синтаксис определения класса на примере:
<?php class first { // Тело класса } ?>
Класс first
из приведенного примера — уже полноправный класс, хотя пока и не слишком полезный. Но тем не менее мы сделали нечто очень важное. Мы определили тип, т.е. создали категорию данных, которые мы можем использовать в своих сценариях. Важность этого станет для вас очевидной по мере дальнейшего чтения главы.
Создание объекта
Так как класс — это шаблон для создания объектов, следовательно, объект — это данные, которые создаются и структурируются в соответствии с шаблоном, определенным в классе. Объект также называют экземпляром класса, тип которого определяется классом. Для создания нового экземпляра класса нам понадобится оператор new. Он используется совместно с именем класса следующим образом:
<?php // Ключевое слово new сообщает интерпретатору PHP о необходимости // создать новый экземпляр класса first $obj1 = new first(); $obj2 = new first(); ?>
После оператора new
указывается имя класса на основе которого будет создан объект. Оператор new
создает экземпляр класса и возвращает ссылку на вновь созданный объект. Эта ссылка сохраняется в переменной соответствующего типа. В результате выполнения этого кода будет создано два объект типа first
. Хотя функционально они идентичны (т.е. пусты) $obj1
и $obj2
— это два разных объекта одного типа, созданных с помощью одного класса.
Если вам все еще не понятно, давайте приведем аналогию из реальной жизни. Представьте, что класс — это форма для отливки, с помощью которой изготавливаются пластмассовые машинки. Объекты — это и есть машинки. Тип создаваемых объектов определяется формой отливки. Машинки выглядят одинаковыми во всех отношениях, но все-таки это разные предметы. Другими словами, это разные экземпляры одного и того же типа.
Давайте сделаем эти объекты немного интереснее, изменив класс
first
, добавив в него специальные поля данных, называемые свойства.
Определение свойств
В классе можно определить переменные. Переменные, которые определены в классе называются свойствами (или полями данных). Они определяются с одним из ключевых слов protected, public
или private
, характеризующих управление доступом. Эти ключевые слова мы рассмотрим подробно в следующей главе. А сейчас давайте определим некоторые свойства с помощью ключевого слова public
:
<?php class first { public $num = 0; public $str = 'some text'; } ?>
Как видите, мы определили два свойства, присвоив каждому из них значение. Теперь любые объекты, которые мы будем создавать с помощью класса first
, будут иметь два свойства с указанными значениями.
Примечание: значения инициализирующие свойства должны быть литералами (константными значениями), инициализировать свойства в классе не обязательно (если значение не указано, по умолчанию это будет NULL
).
К свойствам объекта можно обращаться с помощь символов ‘->
‘, указав объект и имя свойства. Поскольку свойства объектов были определены как public
, мы можем считывать их значения, а также присваивать им новые значения, заменяя тем самым начальные значения, определенные в классе:
<?php class first { public $num = 0; public $str = 'some text'; } $obj = new first(); echo $obj->str; // присваиваем свойству объекта новое значение $obj->str = 'новая строка'; echo "<br>$obj->str"; ?>
На самом деле в PHP необязательно объявлять все свойства в классе. Свойства можно добавлять к объекту динамически:
<?php class first { public $str = 'some text'; } $obj = new first(); // добавляем объекту новое свойство $obj->newprop = 'новое свойство'; echo $obj->newprop; ?>
Нужно отметить, что этот способ присваивания свойств объектам считается дурным тоном в объектно-ориентированном программировании и почти никогда не используется.
Работа с методами
Методы — это обычные функции, которые определяются внутри класса, они позволяют объектам выполнять различные задачи. Объявление метода напоминает определение обычной функции, за исключением предваряемого одного из ключевых слов protected, public
или
private
. Если в определении метода вы опустите ключевое слово, определяющее видимость, то метод будет объявлен неявно как public
. К методам объекта можно обращаться с помощь символов ‘->
‘, указав объект и имя метода. При вызове метода, так же как и при вызове функции нужно использовать круглые скобки.
<?php class first { public $str = 'some text'; // определение метода function getstr() { echo $this->str; } } $obj = new first(); // вызов метода объекта $obj->getstr(); ?>
Мы добавили метод getstr()
к классу first
. Обратите внимание на то, что при определении метода мы не использовали ключевое слово, определяющее область видимости. Это означает, что метод getstr()
относится к типу public
и его можно вызвать за пределами класса.
В определении метода мы воспользовались специальной псевдопеременной $this. Она используется для обращения к методам или свойствам внутри класса и имеет следующий синтаксис:
$this->имя переменной или метода
Значением переменной $this
является ссылка на текущий объект. Чтобы стало понятнее посмотрите на следующий пример:
class first { public $str = 'some text'; // при определении метода в классе, переменная $this не имеет никакого значения function getstr() { echo $this->str; } } // создаем объект $obj = new first(); // созданный нами объект имеет свойство и метод // теперь в методе объекта переменная $this имеет // ссылку на текущий объект, а именно на $obj // т.е. если в методе заменить $this текущим экземпляром объекта $this->str; // это будет выглядеть как простое // обращение к свойству текущего объекта $obj->str;
Примечание: переменной $this
нельзя ничего присваивать. Помните, что переменная $this
всегда ссылается на текущий объект.
Специальный метод — конструктор
У класса может быть определен специальный метод — конструктор, который вызывается каждый раз при создании нового экземпляра класса (объекта) с целью инициализировать его, например установить значения свойств. Конструктор, как и любой другой метод может иметь параметры. Чтобы определить метод в качестве конструктора его необходимо назвать __construct()
. Обратите внимание на то, что имя метода должно начинаться с двух символов подчеркивания. Посмотрим, как это работает:
<?php class first { // определяем два свойства public $num1 = 0; public $num2 = 0; // определяем конструктор класса function __construct($num1, $num2) { $this->num1 = $num1; $this->num2 = $num2; } // метод, который складывает два числа function summa() { return $this->num1 + $this->num2; } } // создаем объект и передаем два аргумента $obj = new first(15, 35); // вызываем метод и сразу выводим результат его работы echo $obj->summa(); ?>
Метод __construct
вызывается, когда создается объект с помощью оператора
new
. Указанные в скобках аргументы передаются конструктору. В методе конструктора используется псевдопеременная $this
для присвоения значений соответствующим свойствам создаваемого объекта.
Указание типа аргумента в методах
По умолчанию метод может принимать аргументы любого типа, но бывают случаи, когда необходимо сделать так, чтобы метод мог принимать в качестве аргумента только экземпляры определенного класса. Для указания типа принимаемого аргумента, просто поместите в определении метода перед именем параметра название класса:
<?php // определяем два пустых класса class cat {} class wrong {} class write { // метод, который принимает аргументы только типа cat function getobj(cat $getCat) { // определяем параметр типа cat echo 'Получен объект типа cat'; } } // создаем экземпляр типа write $kitty = new write(); // работает: передали в качестве аргумента экземпляр типа cat $kitty->getobj( new cat() ); // здесь будет ошибка: передали в качестве аргумента экземпляр типа wrong $kitty->getobj( new wrong() ); ?>
Теперь в качестве аргумента методу getobj()
можно передавать только экземпляры типа
cat
. Поскольку метод getobj()
содержит уточнение типа класса, передача ему объекта типа wrong приведет к ошибке.
Указание типа нельзя использовать для определения параметров элементарных типов, таких как строки, числа и т.д. Для этой цели в теле метода следует использовать функции проверки типов, например is_string()
. Также есть возможность определить, что передаваемый аргумент является массивом:
<?php class write { $my_arr; // аргументом для метода может быть только массив function setArray(array $some_arr) { this->my_arr = $some_arr; } } ?>
И последнее о чем осталось сказать: если параметр метода определяется с указанием определенного класса, разрешается указать значение по умолчанию, на случай, если методу не было передано никакого объекта. В качестве значения по умолчанию может быть использовано только значение NULL
:
function getobj(cat $getCat = null) { $this->someVar = $getCat; }
Если вместо NULL
указать какое-либо другое значение по умолчанию, будет выдана ошибка.
puzzleweb.ru
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.
<?php
// 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.
<?php
$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.
<?php
$objectVar = null;
print_r($objectVar);
print_r($reference);
print_r($assignment);
//
// $objectVar --->+---------+
// | NULL |
// $reference --->+---------+
//
// +---------+
// $assignment -->|(handle1)----+
// +---------+ |
// |
// v
// Object(1):foo="qux"
?>
php.net
Инициализация класса (создание объекта)
Объект класса — представитель класса, который имеет свое уникальное состояние и поведение.
Для объявления объекта необходимо использовать оператор new
:
Объект = new Имя_класса;
PHP
$myObj = new newClass();
Свойства класса
Свойство – это переменные, хранимые в классе; перед именем свойства ставится один из следующих модификаторов (public
, protected
, private
). Также есть ключевое слово var
, но его время ушло (остался в 4-й версии PHP).
Описание свойств
PHP
class newClass { public $property1; protected $property2 = "value2"; private $property3; }
Доступ к свойствам класса
Доступ к свойствам класса за пределами класса реализуется так: объект->имя_свойства;
(знак доллара у свойства не ставится!)
PHP
$myObj = new newClass(); $myObj->property1;
Изменение значения свойств
PHP
$myObj->property2 = "Тут меняем значение";
Методы класса
Метод – это функция, определенная внутри класса. У функции по умолчанию стоит модификатор public
(то есть его можно не писать перед функцией).
Описание методов
PHP
class newClass { function myMethod($var1,$var2){ // по умолчанию это // общедоступный метод (public) // операторы } }
Вызов метода
PHP
$myObj = new newClass(); $myObj->myMethod('v1','v2');
$this
Доступ к свойству класса внутри класса реализуется при помощи оператора($this
):
$this-> имя_свойства;
(знак доллара у свойства не ставится!)
Доступ к методу класса из другого метода класса также осуществляется с помощью ключевого слова $this
.
PHP
class newClass { public $property1; function myMethod(){ echo($this->property1); // Вывод значения свойства } function callMethod(){ $this->myMethod(); // Вызов метода } }
Конструкторы и деструкторы
Конструктор класса – это специальный метод, который автоматически вызывается в момент создания объекта.
Круглый скобки за наименованием класса (при инициализации объекта) нужны для передачи параметров функции конструктору.
Деструктор – специальный метод, который автоматически вызывается при удалении объекта. P.s. Порядок удаления объектов не определен, но стоит отметить, что объекты удалятся по завершении кода (порядок удаления объектов определить нельзя), и вызовется метод __destruct
. Объект можно удалить принудительно: unset(имя_объекта)
.
PHP
class newClass { public $property; function __construct($var){ $this->property = $var; echo "Вызываем конструктор"; } function __destruct(){ echo "Вызываем деструктор"; } } $obj = new newClass("Значение"); //Вызываем конструктор unset($obj); //Вызываем деструктора (принудительно)
Псевдо-константы __METHOD__ и __CLASS__
Псевдо-константы __METHOD__
и __CLASS__
. Вместо __METHOD__
будет подставлено: имя_класса::имя_метода;
__CLASS__
будет подставлено имя_класса
.
PHP
class newClass { function myMethod(){ echo __METHOD__; } function getClassName(){ echo __CLASS__; } } $obj = new newClass(); $obj->myMethod();// newClass::myMethod $obj->getClassName();// newClass
Новые принципы работы с объектами
Объекты передаются по ссылке, а не по значению
PHP
class newClass { public $property; } $myObj = new newClass(); $myObj->property = 1; $myObj2 = $myObj; $myObj2->property = 2; print($myObj->property); // Выведет 2 print($myObj2->property); // Выведет 2
Клонирование объекта
При клонировании (clone
) конструктор не вызывается. Существует специальный метод __clone
, который вызывается при клонировании объекта.
Явное копирование объектов
PHP
class newClass { public $property; } $myObj = new newClass(); $myObj->property = 1; $myObj2 = clone $myObj; // создаем копию объекта, в 4-й версии php было так: $myObj2 = &$myObj; // в 5-й версии PHP & с объектами не работает $myObj2->property = 2; print($myObj->property); // Печатает 1 print($myObj2->property); // Печатает 2
Наследование(полиморфизм)
Один класс может наследовать другой класс. Для этого существует специальное ключевое слово — extends
.
PHP
class Machine { public $numWheels = 4; function printWheels() { echo $this->numWheels; } } class Toyota extends Machine { public $country = 'Japan'; function printCountry() { echo $this->country; } } $myMachine = new Toyota(); $myMachine->printWheels(); $myMachine->printCountry();
Перегрузка методов
Перегрузка методов – в классе, который наследует другой класс, можно описать такой же метод, который есть в родительском классе, причем вновь описанный метод перезапишет метод родительского класса. Пример:
PHP
class Machine { public $numWheels = 4; function printWheels() { echo $this->numWheels; } } class Toyota extends Machine { public $country = 'Japan'; function printCountry() { echo $this->country; } function printWheels() { echo "Перегруженный метод printWheels() "; } } $myMachine = new Toyota(); $myMachine->printWheels();
Parent
parent::имя_метода
, данная конструкция позволяет обратиться к родительскому методу.
PHP
class Machine { public $numWheels = 4; function printWheels() { echo $this->numWheels; } } class Toyota extends Machine { public $country = 'Japan'; function printWheels() { echo "Перегруженный метод printWheels() "; parent:: printWheels(); } } $myMachine = new Toyota(); $myMachine->printWheels();
Модификаторы доступа: public
, protected
, private
Модификатор | Описание |
---|---|
public (общедоступный) |
позволяет иметь доступ к свойствам и методам классам из любого места |
protected (защищенный) |
позволяет иметь доступ и родительскому (в котором определен сам член класса), и наследуемым классам |
private (закрытый) |
ограничивает область видимости так, что доступ к нему имеет только тот класс, в котором объявлен сам элемент |
Модификаторы доступа: как это работает?
PHP
|
PHP
|
PHP
|
PHP
|
Обработка исключений
У нас есть кусок кода, в котором может произойти какая-нибудь ошибка; данный кусок кода помещается в блок под названием try
; в том месте, где-может произойти ошибка, ставится ключевое слово throw
; для отлова произошедшей ошибки описывается блок catch (ловушка), туда приходит ошибка, с которой мы можем работать.
PHP
try { $a = 1; $b = 0; if($b == 0) throw new Exception("Деление на 0!"); echo $a/$b; } catch(Exception $e){ echo "Произошла ошибка - ", $e->getMessage(), // Выводит сообщение " в строке ", $e->getLine(), // Выводит номер строки " файла ", $e->getFile(); // Выводит имя файла }
Создание собственных исключений
PHP
сlass MathException extends Exception { function __construct($message) { parent::__construct($message); } } try { $a = 1; $b = 0; // MathException - имя класса для создания собственного исключения if ($b == 0) throw new MathException("Деление на 0!"); echo $a / $b; } catch (MathException $e) { echo "Произошла математическая ошибка ", $e->getMessage(), " в строке ", $e->getLine(), " файла ", $e->getFile(); }
Перебор свойств объекта
PHP
class Person { public $name; public $yearOfBorn; function __construct($name, $yearOfBorn){ $this->name = $name; $this->yearOfBorn = $yearOfBorn; } } $billGates = new Person(‘Bill Gates’,1955); foreach($billGates as $name=>$value){ print($name.’: ’.$value.’
’); }
Константы класса
Константы – это константы класса, то есть они не принадлежат ни одному объекту. За пределами кода к константе можно обратиться следующим образом: имя_класса::имя_константы
. Если мы хотим обратиться к константе в пределах класса, то нужно использовать ключевое слово self
: self::имя_константы
.
PHP
class Person { const HANDS = 2; function printHands(){ print (self::HANDS);// NOT $this! Обращаемся к константе внутри класса } } print ('Количество рук: '.Person::HANDS); // Обращаемся к константе за пределами класса
Абстрактные методы и классы
Абстрактный класс в php — это так называемый базовый класс, не предназначенный для создания его экземпляров (объектов). Основной смысл и назначение абстрактных классов заключается в расширении возможностей его дочерних классов.
Классы могут быть абстрактными. Абстрактный класс позволяет нам абстрагироваться от незначительных вещей, тем самым предоставляя нам возможность сконцентрироваться на более тонких нюансах.
В абстрактном классе могут быть абстрактные методы (перед function
стоит ключевое слово abstract
). Абстрактный метод – это метод без реализации (отсутствуют фигурный скобки).
Абстрактный метод обязательно должен быть описан (перезагружен) в классе-наследнике. Преимущество в использовании абстрактных методов: для каждого класса-наследника можно описать свое уникальное поведение абстрактного метода.
PHP
abstract class Machine { // абстрактный класс public $petrol; function startEngine(){ print('Двигатель зав?лся!'); } abstract function stopEngine(); } class InjectorMachine extends Machine { public function stopEngine(){ print('Двигатель остановился!'); } } $myMegaMachine = new Machine();//Ошибка! $myMegaMachine = new InjectorMachine(); $myMegaMachine->startEngine(); $myMegaMachine->stopEngine();
Интерфейсы
Существует еще один тип абстрактного класса – интерфейс. Интерфейс – это абстрактный класс, который содержит только абстрактные методы. Перед таким классом вместо слова abstract
пишется interface
. От интерфейса наследование происходит не через ключевое слово extends
, а через ключевое слово implements
.
PHP
interface Hand { function useKeyboard(); function touchNose(); } interface Foot { function runFast(); function playFootball(); } class Person implements Hand { public function useKeyboard(){ echo 'Use keyboard!'; } public function touchNose(){ echo 'Touch nose!'; } public function runFast(){ echo 'Run fast!'; } public function playFootball(){ echo 'Play football!'; } } $vasyaPupkin = new Person(); $vasyaPupkin->touchNose();
Финальные методы и классы
Перед методом ставится ключевое слово final
, этим мы запрещаем перезагружать (перезаписывать) данный метод. Класс также можно объявить финальным.
PHP
class Mathematics { final function countSum($a,$b){ print('Сумма: ' . $a + $b); } } class Algebra extends Mathematics { // Возникнет ошибка public function countSum($a,$b){ $c = $a + $b; print("Сумма $a и $b: $c"); } }
PHP
final class Breakfast { // финальный класс function eatFood($food){ print("Скушали $food!"); } } // Возникнет ошибка class McBreakfast extends Breakfast { // Описание класса }
Статические свойства и методы класса
Статические методы и свойства класса (плюс константы класса) принадлежат классу, то есть они общие для всех объектов класса. К ним нельзя обратиться посредством ‛стрелки‛, а только через ::
(внутри класса используется: self::$имя_свойства
; за пределами класса: имя_класса::$имя_свойства
). Статическое свойство, как и метод, объявляется через ключевое слово static
. Как вы догадываетесь, внутри статического метода this
использовать нельзя (такие методы не связаны с объектами).
PHP
class CookieLover { static $loversCount = 0; // это статическое свойство, и компилятор не // будет его удалять после завершения работы функции __construct function __construct(){ ++self::$loversCount; } static function welcome(){ echo 'Добро пожаловать в клуб любителей булочек!'; //Никаких $this внутри статического метода! } } $vasyaPupkin = new CookieLover(); $frosyaBurlakova = new CookieLover(); print ('Текущее количество любителей булочек: '.CookieLover::$loversCount); print (CookieLover::welcome());
Ключевое слово instanceof
Иногда требуется узнать: является ли текущий объект наследником того или иного класса, или интерфейса. Для этого используется ключевое слово instanceof
.
PHP
class Person {} $myBoss = new Person(); if($myBoss instanceOf Person) print('Мой Босс – человек!'); // вернет true, если класс Person есть в предках объекта $myBoss class Woman extends Person {} $englishQueen = new Woman(); if($englishQueen instanceOf Person) print('Английская королева – тоже человек!'); interface LotsOfMoney {} class ReachPeople implements LotsOfMoney {} $billGates = new ReachPeople(); if($billGates instanceOf LotsOfMoney) print('У Билла Гейтса много денег!');
Функция __autoload()
Если PHP натыкается на несуществующий класс, при инициализации объекта, то он ищет функцию __autoload
, передавая в функцию __autoload
имя неназванного класса. И PHP вызовет эту функцию перед выводом ошибки об отсутствии класса.
PHP
function __autoload($cl_name){ // $cl_name - имя не найденного класса print('Попытка создать объект класса '.$cl_name); } $obj = new undefinedClass();
Методы доступа к свойствам объекта
Метод __set()
будет выполнен при записи данных в недоступные свойства (которых нет в классе).
Метод __get()
будет выполнен при чтении данных из недоступных свойств (которых нет в классе).
PHP
class newClass { private $properties; function __get($name){ print("Чтение значения свойства $name"); return $this->properties[$name]; } function __set($name,$value){ // в нашем случае $name это property, $value равно 1 print("Задание нового свойства $name = $value"); $this->properties[$name] = $value; } } $obj = new newClass; $obj->property = 1; // Запись нового свойства $a = $obj->property; // Чтение значения свойства print $a; // 1
Перегрузка вызова несуществующих методов
Если мы обращаемся к методу которого нет, то PHP ищет метод __call
(1-й параметр – это имя несуществующего метода, 2-й – массив аргументов).
PHP
class newClass { function __call($name, $params){ print("Попытка вызова метода $name со следующими параметрами: "); print_r($params); } } $obj = new newClass(); $obj->megaMethod(1,2,3,"четыре");
Метод __toString()
Метод __toString()
позволяет классу решать самостоятельно, как он должен реагировать при преобразовании в строку. Например, что напечатает echo $obj;
. Этот метод должен возвращать строку, иначе выдастся неисправимая ошибка E_RECOVERABLE_ERROR
.
dnzl.ru
Свойства класса
Создаём свойства. Свойства — это определённые значения по которым мы будем обращаться к классу.
<php class Point{ public $x; public $y; } >?
public — модификатор доступа переменной. Свойство будет доступно из вне класса.
Конструктор класса
Далее мы создаём конструктор класса, через функцию «__construct».
<php class Point{ public $x; public $y; public function __construct($x, $y){ $this->x = $x; $this->y = $y; } } >?
$this — обращаемся к данному объекту. В данном случае к переменным.
Теперь попробуем создать объект.
<php $point = new Point(5,7); echo $point->x."
"; echo $point->y."
"; >?
Мы получили значения элементов через класс. На экран выводиться значения переменных.
Также мы можем манипулировать свойствами объекта, попробуем присвоить значение x=50 и выведем его.
<php $point = new Point(5,7); $point->x = 50; echo $point->x."
"; >?
На экране увидим новое значение.
Методы класса
Методы класса — это по сути функции конкретного класса.
Давайте создадим два метода(функции класса). В первом мы будем получать значение x, а во втором изменять его значение.
<php class Point{ public $x; public $y; public function __construct($x, $y){ $this->x = $x; $this->y = $y; } public function getX(){ return $this->x; } public function setX($x){ $this->x = $x; } } >?
Отлично, теперь мы их опробуем:
<php $point = new Point(5,7); echo $point->getX()."
"; $point->setX(100); echo $point->getX()."
"; >?
На экране мы увидим:
5 100
В начале, мы с помощью функции GetX получили значение, а затем вывели — это 7.
Затем с помощью setX дали переменной новое значение и первой функции вывели его — это 100.
Если мы попробуем просто вывести класс point
echo $point;
То увидим ошибку: «Catchable fatal error: Object of class Point could not be converted to string», чтобы этого избежать используем метод __toString, который уже зарезервирован в php, который возвращает строку, если мы вызываем объект, давайте вставим его в класс.
class Point{ ... public function __toString(){ return "Вывод объекта с координатами (".$this->x."; ".$this->y.")"; } } echo $point;
И после того, как мы вызвали объект через echo, мы увидим на экране значение, которое возвращается через метод.
Вывод объекта с координатами (100; 7)
Также есть метод, который срабатывает при уничтожение объекта(когда объект уже не используется), к примеру если мы его уничтожим через оператор unser($point). Этот метод по умолчанию ничего не выводит, но мы можем это исправить.
class Point{ ... public function __destruct(){ echo "Объект уничтожен"; } }
Также давайте рассмотрим, как передавать объекты. Передадим объект point новому методу.
class Point{ ... public function setPoint($point){ $this->x = $point->x; $this->y = $point->y; } } $new_point = new Point(10,20); $point->setPoint($new_point); echo $point."
";
Теперь разберём. Мы создали новый объект (new_point), затем значения нового объекта передаём нашему point и выводим его.
В этой статье мы подробно разобрали, как создаются : классы, объекты, методы(а также использования зарезервированных), это первый этап в изучении ООП для PHP.
На просторах Youtube нашёл хороший урок по данной статье.
daruse.ru
Наследование
На основе существующих классов можно создавать новые, используя механизм наследования. Механизм наследования — это использование определенного ранее класса в качестве родительского. При этом набор свойств и методов родительского класса можно расширять. Имейте в виду, что производный класс имеет только одного родителя.
Чтобы создать новый класс, наследующий поведение существующего класса, надо использовать ключевое слово extends в его объявлении. Например:
class классN2 extends классN1 { ....... }
Здесь классN1 — родительский класс, классN2 — производный.
Если производный класс не содержит собственного конструктора, то при создании его объекта используется конструктор родительского класса. Если в производном класса существует собственный конструктор, то конструктор родительского класса не вызывается. При необходимости вызвать конструктор родительского класса это надо сделать явно. Например:
классN1::классN1();
Производный класс будет иметь все свойства и методы родительского класса. Но их можно и переопределить в производном классе.
Пример 4
<html> <head> <title>Переопределение метода родительского класса</title> </head> <body> <?php class классN3 { public $имя = "Маша"; function Привет() { echo "<H1>".$this->имя."! Привет!</H1>"; } } class классN4 extends классN3 { function Привет() { echo "<H1>".$this->имя."! Какая встреча!</H1>"; } } $obj = new классN4(); $obj->Привет(); ?> </body> </html>
Метод Привет переопределен для производного класса. Свойство имя наследуется от родительского.
Начиная с 4-й версии PHP, в объекте производного класса можно вызвать метод родительского класса, который был переопределен.
Пример 5
<html> <head> <title>Вызов метода родительского класса</title> </head> <body> <?php class классN5 { public $имя = "Маша"; function Привет() { echo "<H1>".$this->имя."! Привет!</H1>"; } function Пока() { echo "<H1>".$this->имя.", пока!</H1>"; } } /** * Class классN6 */ class классN6 extends классN5 { /** * */ function Привет() { echo "<H1>".$this->имя."! Какая встреча!</H1>"; классN5::Привет(); } } $obj = new классN6(); $obj->Привет(); $obj->Пока(); ?> </body> </html>
Итак, производный класс может наследовать, переопределять и дополнять свойства и методы другого класса.
В следующем примере создан класс HTMLTable, основанный на классе Table из примера 3. Новый класс формирует данные, сохраненные методом addRow родительского класса, и выводит их в HTML-таблицу. Свойства $cellpadding и $bgcolor дают возможность изменять соответствующие аргументы, при этом переменной $cellpadding присваивается значение по умолчанию, равное 2.
Пример 6
<html> <head> <title>Классы Table и HTMLTable</title> </head> <body> <?php class Tables { public $headers = []; public $data = []; function Tables( $headers ) { $this->headers = $headers; } function addRow ( $row ) { $tmp = []; foreach ( $this->headers as $header ) { if ( ! isset( $row[$header] )) $row[$header] = ""; $tmp[] = $row[$header]; } array_push ( $this->data, $tmp ); } function output () { echo "<PRE><B>"; foreach ( $this->headers as $header ) echo "$header "; echo "</B><BR>"; foreach ( $this->data as $y ) { foreach ( $y as $x ) echo "$x "; echo "<BR>"; } echo "</PRE>"; } } class HTMLTable extends Tables { public $cellpadding = "2"; public $bgcolor; function HTMLTable ( $headers, $bg="FFFFFF" ) { Tables::Tables( $headers ); $this->bgcolor = $bg; } function setCellpadding ( $padding ) { $this->cellpadding = $padding; } function output () { echo "<table cellpadding='".$this->cellpadding."'><tr>"; foreach ( $this->headers as $header ) echo "<th bgcolor='".$this->bgcolor."'>".$header; foreach ( $this->data as $y ) { echo "<tr>"; foreach ( $y as $x ) echo "<td bgcolor='".$this->bgcolor."'>$x"; } echo "</table>"; } } $test = new HTMLTable ( array("a","b","c"), "#00FFFF" ); $test->setCellpadding ( 7 ); $test->addRow(array("a"=>1,"b"=>3,"c"=>2)); $test->addRow(array("b"=>1,"a"=>3)); $test->addRow(array("c"=>1,"b"=>3,"a"=>4)); $test->output(); ?> </body> </html>
Обратите внимание на то, что значение свойства сellpadding меняется с помощью отдельного метода setCellpadding. Конечно, значения свойств можно менять непосредственно, вне объекта:
$test->сellpadding = 7 ;
Но это считается дурным тоном, т.к. в сложных объектах при изменении одного из свойств могут изменяться и другие свойства.
Использовать или нет технику объектного программирования? С одной стороны, проект, интенсивно использующий объектную технику, может занимать слишком много ресурсов во время выполнения. С другой стороны, правильно организованный объектный подход значительно сократит время разработки и сделает программу более гибкой.
Удаление объектов
Удалить ранее созданный объект можно следующим образом:
unset($objName);
Ниже приведен пример, в котором объект класса Саг создается, а затем удаляется.
$myCar = new Car; unset($myCar);
После вызова функции unset() объект больше не существует. В РНР имеется специальный метод __destruct(), который автоматически вызывается при удалении объекта. Ниже приведен класс, содержащий этот метод.
class Bridge { function __destruct() { echo "Мост разрушен"; } } $bigBridge = new Bridge; unset($bigBridge);
При создании объекта класса Bridge, а затем его удалении отобразится следующее сообщение:
Мост разрушен
Оно отображается вследствие вызова метода __destruct() при вызове функции unset(). При удалении объекта может потребоваться акрыть некоторые файлы или записать информацию в базу данных.
Копирование (клонирование) объекта
Клонирование объекта:
$a = clone $b;
Конструктор не вызывается при клонировании, вызывается магический метод __clone(){}
. Он НЕ принимает аргументов и к нему нельзя обратиться как к методу.
Преобразование объекта в строку
Для конвертации объекта в строку, и обратно, используются следующие функции:
serialize() — принимает объект и возвращает строковое представление его класса и свойств;
unserialize() — принимает строку, созданную при помощи serialize(), и возвращает объект.
serialize() и unserialize() работают со всеми типами данных, но они не работают с ресурсами.
Специальные методы для обслуживания функций serialize() и unserialize():
__sleep() — вызывается строго перед тем, как объект сериализуется с помощью функции serialize(). Функция __sleep() должна будет вернуть список полей класса, которые функция serialize() включит в возвращаемую строку. Вы можете использовать это для того, чтобы исключить ненужные поля из строкового представления объекта. Например:
public function __sleep() { // почистить return array_keys( get_object_vars( $this ) ); }
__wakeup() — вызывается сразу после того, как объект десериализуется с помощью unserialize().
Абстрактный класс
Абстрактный класс — это класс, который не может быть реализован, то есть, вы не сможете создать объект класса, если он абстрактный. Вместо этого вы создаете дочерние классы от него и спокойно создаете объекты от этих дочерних классов. Абстрактные классы представляют собой шаблоны для создания классов.
abstract class Person { private $firstName = ""; private $lastName = ""; public function setName( $firstName, $lastName ) { $this->firstName = $firstName; $this->lastName = $lastName; } public function getName() { return "$this->firstName $this->lastName"; } abstract public function showWelcomeMessage(); /* абстрактный метод showWelcomeMessage(). Так как он абстрактный, в нем нет ни строчки кода, это просто его объявление. Любой дочерний класс обязан добавить и описать метод showWelcomeMessage() */ }
Интерфейс
Интерфейс — это шаблон, который задает поведение одного или более классов. Вот основные отличия между интерфейсами и абстрактными классами:
- Ни один метод не может быть описан в интерфейсе. Они все абстрактны. В абстрактном классе могут быть и не абстрактные методы.
- Интерфейс не может содержать полей — только методы.
- Класс имплементирует интерфейс, и класс наследует или расширяет другой класс.
- Класс может имплементировать несколько интерфейсов одновременно. Этот же класс может наследовать другой класс. Но у дочернего класса может быть только один супер-класс (абстрактный или нет).
interface MyInterface { public function aMethod(); public function anotherMethod(); } class MyClass implements MyInterface { public function aMethod() { // (имплементация метода) } public function anotherMethod() { // (имплементация метода) } }
Методы-перехватчики (магические методы)
- __get($property) — вызывается при обращении к неопределенному свойству
- __set($property,$value) — вызывается, когда неопределенному свойству присваивается значение
- __unset($property) — вызывается, когда функция unset() вызывается для неопределенного свойства
- __isset($property) — вызывается, когда функция isset() вызывается для неопределенного свойства
- __call($method,$arg array) — вызывается при обращении к неопределенному методу
- __callStatic($method,$arg array) — вызывается при обращении к неопределенному статическому методу
- __toString() — Вызывается, если есть попытка вывести объект, как строку.
- __debugInfo() — В PHP 5.6 был добавлен новый магический метод, который позволяет менять свойства и значения объекта, когда он печатается с помощью функции var_dump(класс).
- __invoke() — для вызова объекта как функции. Пример
Пример использования необъявленных свойств класса
Где и зачем могут быть использованны методы-перехватчики?
Например есть у вас таблица в базе данных, называется user и есть в ней некие поля, например id, name, email, phone, password, avatar И Вы создали класс на для работы с юзерами, так его и назвали — User
Какие свойства будут у данного класса? Если вы сделаете такие же как в БД — id, name, email и так далее, то получается что при каждом изменении базы данных — вам нужно менять код в классе User, как то не очень удобно. Добавили вы например поле site — значит нужно его добавлять и в класс User, ну и так далее.
Используя же методы __get() и __set() Вы можете это всё автоматизировать. У вас в классе User вообще не будет ни одного свойства из БД, у нас есть допустим только одно $data — мы туда взяли, да и загрузили всё что есть в базе данных на данного пользователя. А потом, когда программист что то запрашивает, например $user->email мы просто в __get() методе можете посмотреть — если мы такую информацию загрузили из БД, и она лежит в $data[’email’] — то вот мы её вам и возвращаем. А в __set() наоборот. Есть такое поле в БД? Значит присвоим ему новое значение.
/** * Class User * @property-read integer id текущего пользователя * @property-write String site возвращает ссылку на сайт пользователя */ class User { private $data; private $f_write=false; public function __set($name, $value) { $this->data[$name] = $value; $this->f_write=true; // признак, что нужно сохранить данные } public function __get($name) { if(empty($data)){ // читаем запись из БД в data } return $this->data[$name]; } function __destruct() { if(!empty($data)&&$this->f_write){ // сохраняем изменения в БД } } } $user=new User(); $user->site='http://kdg.htmlweb.ru/'; //присваеваем переменной echo $user->site; //выводим значение переменной // записываем в БД. Можно это явно не делать, т.к. при окончании работы скрипта это поизойдет автоматически unset($user);
Пример использование необъявленного свойства класса как элемент массива
Обратите внимание на то, что из __get возвращается ссылка:
class Foo { private $data = []; public function __set($name, $value) { $this->data[$name] = $value; } public function & __get($name) { return $this->data[$name]; } } $foo = new Foo(); $foo->bar[2] = 'lol'; var_dump($foo->bar);
Использоватние перехватчиков обращения к необъявленным методам класса
class OurClass { public function __call($name,array $params) { echo 'Вы хотели вызвать $Object->'.$name.', но его не существует, и сейчас выполняется '.__METHOD__.'()'; return; } public static function __callStatic($name,array $params) { echo 'Вы хотели вызвать '.__CLASS__.'::'.$name.', но его не существует, и сейчас выполняется '.__METHOD__.'()'; return; } } $Object=new OurClass; $Object->DynamicMethod(); OurClass::StaticMethod();
Пример обхода закрытых метов класса:
class _byCallStatic{ // Пример обхода "закрытых" методов класса, // при использовании метода "__callStatic()" для вызова статического метода. public static function __callStatic($_name, $_param) { return call_user_func_array('static::'. $_name, $_param); } private static function _newCall(){ echo 'Method: '. __METHOD__; } } echo _byCallStatic::_newCall(114, 'Integer', 157); # Результат: Method: _byCallStatic::_newCall
Как вызвать через статический метод любой динамический:
/** * Class o * @method static void __f(int $a1 = 1) */ class o { public static function __callStatic($method, $args) { $class = get_called_class(); $obj = new $class($args[0]); $method = substr($method, 2); $pass = array_slice($args,1); $reflection = new ReflectionMethod($obj, $method); return $reflection->invokeArgs($obj, $pass); } public function f($a1 = 1) { var_dump('oo', func_get_args()); } } class a extends o { public function f($a1 = 1, $a2 = 2) { var_dump('aa', $a1 ); } } class b extends o { public function f($b1 = 1) { var_dump('bb', $b1); } } a::__f(1,2,3); b::__f(4,5,6);
Полезное описание работы с ReflectionClass, когда вы можете проанализировать свойства и методы класса, проверить параметры по шаблонам и т.д.: http://habrahabr.ru/post/139649/
Как использовать объект как функцию?
class Dog { private $name; public function __construct($dogName = 'Тузик') { $this->name = $dogName; } public static function __invoke() { $args = func_get_args(); echo 'Собака получила: ' . implode(' и ', $args); } } $dog = new Dog('Мухтар'); $dog('кость', 'поводок');
Как обращаться к объекту как к массиву?
Для этого необходимо создать такой объект который реализует интерфейс ArrayAccess из SPL. Следующий пример реализует объект доступ к данным которого можно получать как в стиле обращения к массиву, так и через получение свойств:
class MyArray implements ArrayAccess { protected $arr = array(); public function offsetSet($key, $value) { $this->arr[$key] = $value; } public function offsetUnset($key) { unset($this->arr[$key]); } public function offsetGet($key) { return $this->arr[$key]; } public function offsetExists($key) { return isset($this->arr[$key]); } public function __get($key) { return $this->offsetGet($key); } public function __set($key, $val) { $this->offsetSet($key, $val); } } $a = new MyArray(); $a['whoam'] = 'Я значение массива, или объекта? <br/ >'; echo $a['whoam']; echo $a->whoam;
Автозагрузка классов
Файлы автозагружаемых классов обычно располагаются в общем месте, например в /include/class/. Имя файла формируется в формате ИМЯ_КЛАССА.php. Данный код необходимо подключить во все PHP-скрипты:
spl_autoload_register(function ($class_name) { //echo "Autoload ".$class_name; $file = $_SERVER['DOCUMENT_ROOT'] . "/include/class/" . strtolower($class_name) . '.php'; if (file_exists($file) == false) { if($GLOBALS['DEBUG']) echo "Нет файла ".$file; return false; } include_once($file); return true; });
Для автоподгрузки классов можно также использовать определение функции __autoload();
htmlweb.ru