Разделы
Теги | RSS © 2008 – 2017
Контакты
email: igor@veselov.sumy.ua
skype: utz0r2
» » » Страница 4

5. Коротко ООП PHP - Абстрактные классы (abstract) и интерфейсы объектов (interface), их отличие


Методы, объявленные абстрактными, несут, по существу, лишь описательный смысл и не могут включать реализации. При наследовании от абстрактного класса, все методы, помеченные абстрактными в родительском классе, должны быть определены в классе-потомке; кроме того, область видимости этих методов должна совпадать (или быть менее строгой).
Интерфейсы объектов позволяют создавать код, который указывает, какие методы должен реализовать класс, без необходимости описывания их функционала. Тела методов интерфейсов должны быть пустыми.
Интерфейс - это абстрактный класс, у которого все методы не реализованы, все публичные и нет переменных класса.
Абстрактный класс - это как ЗАГОТОВКА.
Интерфейс - это как КОНТРАКТ, что обязан выполнять класс.
А теперь в чем же отличие:
- Интерфейсы, в отличии от абстрактных классов, поддерживают множественное наследование. Т.е. класс-потомок может реализовывать 2 или более интерфейсов одновременно: class A implements Int1, Int2, но class A extends AbstrB
- Интерфейс содержит исключительно объявления методов, но не содержит реализации.
- Интерфейс не может включать в себя свойства
- Класс-потомок обязан реализовывать все методы интерфейса
- В интерфейсе все методы открытые
abstract
<?php

abstract class Car {
	public $x;
	public $y;

    public function __construct($x, $y) {
      $this->x = $x;
      $this->y = $y;
    }
	
	abstract public function move ($x, $y);

}

class BMW extends Car {
	
    public function move($x, $y) {
		echo "Движение BMW из координат ($this->x, $this->y) в координаты ($x, $y)<br />";
		$this->x = $x;
		$this->y = $y;
    }
	
}

$auto = new BMW(10, 20);
echo $auto->x;
echo "<br />";
echo $auto->y;
echo "<br />";
$auto->move(5, 15);
interface
<?php

interface Parsed {
	public function Parsed($blah);
}

interface DotSyntax {
	public function UsesDotSyntax();
}

interface Compiled {
	public function isCompiled();
}



class Java implements DotSyntax, Compiled {
	public function __construct() {
		echo 'Java was created<br/>';
		$this->UsesDotSyntax();
		$this->isCompiled();
	}

	public function UsesDotSyntax() {
		echo 'Yes, UsesDotSyntax<br/>';
	}

	public function isCompiled() {
		echo 'Yes, isCompiled<br/>';
	}
}

class PHP implements Parsed {
	public function __construct() {
		echo 'PHP was created<br/>';
		$this->Parsed('Yes, Parsed<br/>');
	}
	public function Parsed($blah) {
		echo $blah;
	}
}

$php = new PHP();
$java = new Java();

4. Коротко ООП PHP - Магические методы (magic methods) __


Магиеские методы - "магия" данных методов сводится к тому, что они могут перехватывать (отсюда их второе название - методы-перехватчики) сообщения, посланные неопределенным (по сути - несуществующим) методам и свойствам
Всегда начинаются с двойного подчеркивания.
__construct() - этот метод запускается автоматически при созданнии экземпляра класса
__destruct() - метод запускается автоматически при уничтожении обьекта
__call(), __callStatic() - перехватывают обращение к несуществующему методу в контексте объекта и в статическом контексте
__get(), __set() - выполняется при чтении/записи данных из недоступных свойств
__isset() - будет выполнен при использовании isset() или empty() на недоступных свойствах
__unset() - будет выполнен при вызове unset() на недоступном свойстве
__sleep() - вызывается, когда объект подвергается сериализации при помощи функции serialize()
__wakeup() - вызывается при восстановлении объекта при помощи функции unserialize()
__toString() - метод, с помощью которого можно обращаться к классу как к строке
__invoke() - вызывается при попытке использовать объект в качестве функции
__set_state() - метод, который вызывается для классов, экспортирующих значения свойств функцией var_export()
__clone() - вызывается при клонировании объекта
__debugInfo() - метод вызывается функцией var_dump(), когда необходимо вывести список свойств объекта
<?php
class Car {

	function __construct() {
		echo 'Конструктор, вызывается автоматически во время создания экземпляра класса <br/>';
	}

	function __destruct() {
		echo 'Деструктор, вызывается автоматически во время уничтожения экземпляра класса <br/>';
	}

    function __call($name, $arguments) {
        // значение $name регистрозависимо
        echo "Вызов метода '$name' " . implode(', ', $arguments). "<br/>";
    }

    static function __callStatic($name, $arguments) {
        echo "Вызов статического метода '$name' " . implode(', ', $arguments). "<br/>";
    }

	function __get($param) {
		echo "Выполнить из за чтения данных из недоступных свойств: $param <br/>";
	}
	
	function __set($name, $value) {
		echo "Выполнить метод из за записи данных в недоступные свойства: $name -> $value <br/>";
		return $this->{$name} = $value; 
	}

    function __isset($name) {
        echo "Установлено ли '$name'? <br/>";
        // return isset($this->data[$name]);
    }

    function __unset($name) {
        echo "Уничтожение '$name' <br/>";
        // unset($this->data[$name]);
    }
	
	function __sleep() {
		echo "Объект подвергается сериализации при помощи функции serialize <br/>";
    }	
	
	// function __wakeup() {
		// echo "Объект подвергается восстановлении при помощи функции unserialize <br/>";
    // }	
	
	function __toString() {
		return "Мы вызвали " . __METHOD__ . "<br/>";
	}
	
	function __invoke($vars) {
		return "Нельзя вызывать класс как функцию <br/>";
	}
	
	function __set_state($an_array) {
		return print_r($an_array) . "<br/>";
	}

	function __clone()	{
		echo 'Вызывается при клонировании объекта <br/>';
	}

	function __debugInfo() {
		echo 'Вызывается при var_dump <br/>';
	}
	
}

$car = new Car();	// __construct
$car->runTest('в контексте объекта');	// __call
car::runTest('в статическом контексте объекта'); // __callStatic
$car->asdfasdf;	// __get
$car->asdfasdf = 'test';	// __set
isset($car->a); // __isset
isset($car->b); // __unset
$a = serialize($car); // __sleep
// unserialize($a); // __wakeup
echo $car; // __toString
echo $car('Пиу'); // __invoke
eval('$b = ' . var_export($car, true) . ';'); 
var_dump($b); // __set_state
$car2 = clone $car; // __clone
var_dump($car2); // __debugInfo

3. Коротко ООП PHP - Обьявление как статические (static) и финальные (final).


Объявление свойств и методов класса статическими позволяет обращаться к ним без создания экземпляра класса.
Финальные классы используются для запрета унаследования, а методы для запрета переопределения.
<?php
class Car {
	
	// доступ к статическим свойствам класса не может быть получен через оператор ->
	public static $name = 'БМВ';
	
	public static function run() {
		
		// псевдо-переменная $this не доступна внутри статического метода
		echo self::$name . ' Едь!';
		
	}
	
}

// final - класс CarAlien не может быть унаследован
final class CarAlien extends Car {
	
	// final - метод Hi не может быть переопределен
    final public static function run() {
		
		// псевдо-переменная $this не доступна внутри статического метода
		echo 'Мы приехали с миром '  .parent::$name . '!';
		
    }
	
}

echo Car::$name;

echo "<br/>";

Car::run();

echo "<br/>";

CarAlien::run();
Использовать статические функции класса можно, не создавая самого экземпляра класса - это экономит память.

2. Коротко ООП PHP - Принципы: инкапсуляция, полиморфизм, наследование


Обьект Car в жизни это слишком обобщенно. Поэтому создадим машины унаследовав родитель-класс Car (наследование), имзеним их свойства и методы при необходимости (полиморфизм), и ограничим области видимости свойств и методов с помощью спецификаторов доступа private, protected, public ( инкапсуляция(сокрытие внутренних процессов)).
<?php
class Car {

	const DOORS = 5;
	const TYPE = 'хетчбек';

	// инкапсуляция	(ограничили область видимости свойств odo только классом Car и его наследникми)
	protected $odo;
	
	public $fuel = 100;
	public $speed = 0;

	public function run( $speed = 0, $time = 0 ) {
		$this->speed = $speed;
		$this->odo = $speed*$time;
		return 'Движемся со скоростью: ' . $speed . ' км/ч. В течении '  .$time . ' часов <br/>';
	}

	public function stop() {
		$this->speed = 0;
		return 'Остановились, наша скорость: 0 км/ч <br/>' . $this->getOdo();
	}

	// инкапсуляция (ограничили область видимости метода getOdo только классом Car)
	private function getOdo () {
		return 'Проехали дистанцию: ' . $this->odo . ' км <br/>';
	}
	
}

// наследование (наследуем класс родитель Car)
class Zaz extends Car {
	
	// полиморфизм (переопределили константы DOORS и TYPE для Zaz)
	const DOORS = 4;
	const TYPE = 'седан';
	
	// полиморфизм (переопределили свойство $fuel)
	public $fuel = 40;

	// расширили новым методом zagloh только для класса Zaz 
	public function zagloh () {
		return 'Заглох... <br/>';
	}
	
}

// наследование (наследуем класс родитель Car)
class Amfibia extends Car {

	// полиморфизм (переопределили метод run, все остальное осталось от класса Car)
	public function run ( $speed = 0, $time = 0, $water = 0 ) {
		$this->speed = $water == 1? $speed/3 :	$speed;
		$this->odo = $this->speed*$time;
		return 'Движемся со скоростью: ' . $this->speed . ' км/ч. В течении '  .$time . ' часов <br/>';
	}
	
	// рашсирили родительский метод stop
	public function stop() {
		return 'Пшшшш... ' . parent::stop();
	}
	
}


// Cоздаем экземпляр объекта класса Zaz
$car = new Zaz();
echo 'У машины: ' . $car::DOORS . ' двери<br/>';
echo 'Тип машины: ' . $car::TYPE . '<br/>';
echo 'В баке: ' . $car->fuel . ' л топлива<br/>';
echo 'Текущая скорость машины: ' . $car->speed . ' км/ч<br/>';
echo $car->run();
echo $car->zagloh();
echo $car->run(60, 10);
echo $car->stop();

// Cоздаем экземпляр объекта класса Amfibia
$car2 = new Amfibia();
echo 'По воде: ' . $car2->run(60, 10, 1);
echo $car2->stop();

1. Коротко ООП PHP - Класс (class) и его объект (object)


Класс – это способ описания сущности. И по классу создается объект (экземпляр класса).
Если абстрогироваться еще больше, то класс - это чертеж автомобиля, а обьект - это сам автомобиль собраный по чертежу. Рассмотрим пример.
<?php
class Car {
	
	// константы
	const DOORS = 5;
	const TYPE = 'хетчбек';
	
	// свойства
	public $fuel = 100;
	public $speed = 0;
	public $odo;
	public $status = 'хорошее';
	
	// метод run ( имеет входные параметры скорость и время )
	public function run( $speed = 0, $time = 0 ) {
		// $this это обращение к переменной или методу в контексте класса
		$this->speed = $speed;
		$this->odo = $speed * $time;
		return 'Движемся со скоростью: ' . $speed . ' км/ч. В течении '  .$time . ' часов';
	}
	
	// метод stop
	public function stop() {
		$this->speed = 0;
		return 'Остановились, наша скорость: 0 км/ч';
	}

	// метод getOdo
	public function getOdo () {
		return 'Проехали дистанцию: ' . $this->odo . ' км';
	}
	
}

// Cоздаем экземпляр объекта класса Car
$car = new Car();

// Вызов констант
echo 'У машины: ' . $car::DOORS . ' дверей<br/>';
echo 'Тип машины: ' . $car::TYPE . ' <hr/>';

// Текущие свойства
echo 'В баке: ' . $car->fuel . ' л топлива<br/>';

// Операция над свойством
$car->fuel = $car->fuel/2; // Слили половину =)

echo 'Теперь в баке: ' . $car->fuel . ' л топлива<br/>';
echo 'Текущая скорость машины: ' . $car->speed . ' км/ч<hr/>';

// Выполнение методов
echo $car->run() . '<br/>';
echo $car->run(60,10) . '<br/>';
echo $car->stop() . '<br/>';
echo $car->getOdo();

0. Коротко ООП PHP - Плюсы и минусы


Начинаю серию постов под названием "Коротко ООП PHP". В цикле затрону основные моменты обьектно ориентированного программирования на PHP. А сегодня начнем с плюсов и минусов. Подразумевается, что вы вкурсе что такое PHP на уровне новичка.

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

Минусы: производительность, она ниже. Необходимо понимать базовые концепции. Проектирование классов не всегда просто, и скорей всего придеться переписывать, пока не научишся на ошибках. Документировать классы сложней, т.к. методы могут переопределяться. Иногда сложно понять какие поля и методы относятся к данному классу из за сложности ирархии классов и приходится просматривать весь код. В библиотечном классе часто содержится больше методов, чем это реально необходимо.

Цитата из книги, которая ставит все на место:
Процедурный код (код, использующий структуры данных) позволяет легко добавлять новые функции без изменения существующих структур данных. Объектно - ориентированный код, напротив, упрощает добавление новых классов без изменения существующих функций.
Обратные утверждения также истинны.
Процедурный код усложняет добавление новых структур данных, потому что оно требует изменения всех функций. Объектно-ориентированный код усложняет добавление новых функций, потому что для этого должны измениться все классы.
Таким образом, то, что сложно в ОО, просто в процедурном программировании, а то, что сложно в процедурном программировании, просто в ОО!

«»
Вверх