Интерфейсы и контроль типа. Оператор instanceof в ООП PHP

Интерфейсы и контроль типа
Оператор instanceof



Контроль типа

Оператор instanceof

Использование контроля типа совместно с интерфейсом



Интерфейсы очень удобно применять вместе с контролем типа.

Совместно с контролем типа интерфейсы предоставлют способ проверки того, что определенный объект может содержать некоторый набор методов.



Контроль типа


Оператор instanceof




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

Для примера в индексном файле (index.php) создадим три класса без реализации:


Создадим три класса без реализации:
- class A {}; - класс A
- class B extends A {}; - класс B, который будет наследовать класс A,
- class C {}; - класс C
Создадим три объекта от этих классов:
- $a = new A;
- $b = new B;
- $c = new C;



С помощью оператора instanceof (оператор проверки типов:php.net) сделаем проверку и получим после их распечатки (var_dump):


- var_dump($a instanceof A); - выведет boolean true
- var_dump($b instanceof B); - выведет boolean true
- var_dump($c instanceof A); - выведет boolean false



- читается, например, является ли объект $a экземпляром класса A, возвращает TRUE или FALSE.


Вместо ($b instanceof B) запишем ($b instanceof A) и распечатаем:


- var_dump($b instanceof A); - получим boolean true



- потому, что класс B расширяет класс A, он его наследует, и соответственно, наш объект $b является экземпляром двух классов: и класса B, и класса A



Использование контроля типа совместно с интерфейсом




В индексном файле создадим функцию, например, предложение какого-нибудь чехла (offerCase).

На вход будет подаваться некий продукт (объект) - $product и для него мы будем предлагать некий чехол:


function offerCase($product)
{
echo "<p>Предлагаем чехол для гаджета {$product->getName()} </p>" ;
}
- имя получаем через геттер getName() из класса Product



Создадим новый объект - ноутбук: $notebook = new NotebookProduct('Dell', 1000, 'Intel' ), у данного объекта есть свойство $name(имя)- оно приватное и получить мы его можем через геттер getName().

Вызовем функцию offerCase($notebook), где $notebook - в качестве параметра.

В результате работы этой функции в браузере будет выведено:


- Предлагаем чехол для гаджета Dell



Если мы вызовем функцию для объекта книжка - offerCase($book), то получим:


- Предлагаем чехол для гаджета Три мушкетера




файл index.php:


-- файл index.php --

<?php
error_reporting(-1);
require_once 'classes/Product.php';
require_once 'classes/I3D.php';
require_once 'classes/NotebookProduct.php';
require_once 'classes/BookProduct.php';

function debug($data)
{
echo '<pre>' . print_r($data, 1 ) . '</pre>';
}

// создадим функцию (предложение какого-нибудь чехла)
// на вход будет подаваться некий продукт $product - function offerCase($product)
function offerCase($product)
{
echo "<p>Предлагаем чехол для гаджета {$product -> getName()} </p>";
}

$book = new BookProduct('Три мушкетера', 20, 1000);

// создадим новый объект
$notebook = new NotebookProduct('Dell', 1000, 'Intel');

// вызовем функцию offerCase() с параметром $notebook
offerCase($notebook);

// предлагаем чехол для гаджета Три мушкетёра
offerCase($book);

debug($book);

echo $book -> getProduct();

// Контроль типа
// для примера создадим 3 класса:
class A {}; // класс A
class B extends A {}; // класс B, который будет наследовать класс A
class C {}; // класс C
// создадим 3 объекта от этих классов
$a = new A;
$b = new B;
$c = new C;

// с помощью оператора instanceof (оператор проверки типов) сделаем проверку:
// читается: является ли объект $a экземпляром класса A, возвращает TRUE или FALSE
//var_dump($a instanceof A); // выведет true
//var_dump($b instanceof B); // выведет true
//var_dump($c instanceof A); // выведет false
var_dump($b instanceof B);
var_dump($b instanceof A);
// - выведет true, так как $b является объектом двух классов: A и B
// (так как класс B расширяет класс A (наследует))
// Объект является экземпляром всех классов, которые есть у него в родословной

?>

Выведет:
Предлагаем чехол для гаджета Dell (offerCase($notebook));
Предлагаем чехол для гаджета Три мушкетера (offerCase($book));

BookProduct Object
(
[numPages] => 1000
[name:Product:private] => Три мушкетера
[price:protected] => 20
[discount:Product:private] => 5
)

О товаре:
Наименование: Три мушкетера
Цена со скидкой: 19
Цена без скидки: 20
Кол-во страниц: 1000
Скидка: 5%

boolean true (var_dump($b instanceof B));
boolean true (var_dump($b instanceof A));




- такая ситуация может возникнуть и с ней надо как-то бороться. Здесь на помощь нам приходят интерфейсы и контроль типов.

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


Создадим интерфейс IGadget:


-- файл IGadget --

<?php
// Совместно с контролем типов и интерфейсов мы можем дать средство пользователю проверять,
// что определенный объект, в нашем случае - ноутбук,
// должен содержать определенный набор методов (предлагаемые чехлы должны
// подходить под данный продукт)
// создадим интерфейс IGadget
interface IGadget
{
public function getCase(); // публичный метод getCase() без реализации
}
?>




Наши ноутбуки должны реализовывать данный интерфейс (в NotebookProduct.php). Если интерфейс будет пустым, то ничего реализовывать мы не будем.


Файл NotebookProduct.php


-- файл NotebookProduct.php --

<?php

// реализуем интерфейс IGadget в классе NotebookProduct
class NotebookProduct extends Product implements IGadget
{
public $cpu;

public function __construct($name, $price, $cpu)
{
parent :: __construct($name, $price);
$this -> cpu = $cpu;
}

// в нашем классе мы обязательно должны реализовать интерфейсный метод getCase()
public function getCase()
{
//...
}

public function getProduct()
{
$out = parent :: getProduct();
$out .= "Процессор: {$this -> cpu}<br>";
return $out;
}

public function getCpu()
{
return $this -> cpu;
}

public function addProduct($name, $price, $cpu = '')
{
// --------------------------
var_dump($name);
var_dump($price);
var_dump($cpu);
}
}
?>





Подключим интерфейс IGadget в индексном файле (index.php).

И делаем проверку:


- var_dump($notebook instanceof NotebookProduct); - получаем boolean
- var_dump($notebook instanceof IGadget); - получаем boolean true
- var_dump($book instanceof IGadget); - получаем boolean false



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

Воспользуемся контролем типов и укажем, что данной функции на вход должен обязательно передаваться параметром объект и объект вполне конкретного класса (IGadget):


- offerCase(IGadget $product)




файл index.php:


-- файл index.php --

<?php
error_reporting(-1);

// ВНИМАНИЕ: нужно соблюдать порядок подключения !!!
require_once 'classes/Product.php';
require_once 'classes/I3D.php';
// подключаем интерфейс IGadget.php
require_once 'classes/IGadget.php';
require_once 'classes/NotebookProduct.php';
require_once 'classes/BookProduct.php';

function debug($data)
{
echo '<pre>' . print_r($data, 1 ) . '</pre>';
}

// создавая метод offerCase мы можем воспользоваться контролем типов совместно с интерфейсами
function offerCase(IGadget $product)
{
echo "<p>Предлагаем чехол для гаджета {$product -> getName()} </p>";
}

$book = new BookProduct('Три мушкетера', 20, 1000);

$notebook = new NotebookProduct('Dell', 1000, 'Intel');

// вызовем функцию offerCase() с параметром $notebook
offerCase($notebook);

// для проверки:
// попытка предложить чехол для гаджета Три мушкетёра
// при отработки function offerCase(IGadget $product) - вызовет ошибку
// offerCase($book);

// делаем проверку:
// в браузере получаем boolean true - это значит, что наш ноутбук ($notebook - объект)
// является экземпляром класса NotebookProduct
var_dump($notebook instanceof NotebookProduct);

// и одновременно он является экземпляром интерфейса (класса) IGadget
var_dump($notebook instanceof IGadget);

// в то время, как $book не является экземпляром интерфейса IGadget; (boolean false)
var_dump($book instanceof IGadget);

// распечатаем объект
debug($book);

// получаем информацию о продукте с помощью метода getProduct()
echo $book -> getProduct();
//echo $notebook->getProduct();

?>

Получим:
Предлагаем чехол для гаджета Dell (offerCase($notebook));
boolean true (var_dump($notebook instanceof NotebookProduct));
boolean true (var_dump($notebook instanceof IGadget));
boolean false (var_dump($book instanceof IGadget));

BookProduct Object
(
[numPages] => 1000
[name:Product:private] => Три мушкетера
[price:protected] => 20
[discount:Product:private] => 5
)

О товаре:
Наименование: Три мушкетера
Цена со скидкой: 19
Цена без скидки: 20
Кол-во страниц: 1000
Скидка: 5%

boolean true (var_dump($b instanceof B));
boolean true (var_dump($b instanceof A));




Содержание папки 11 ("Интерфейсы и контроль типа"):


11-1






Наверх Наверх