|
Як відомо в програмуванні в середовищі PHP в основному використовуються такі парадигми програмування як процедурне і об'єктно-орієнтовне програмування. Розглянемо ці парадигми детальніше:
Процедурне програмування. Робота цієї концепції заснована на виклику так званих процедур (методи, функції, ...). Кожна процедура містить певну логіку для виконання тих чи інших операцій і може бути викликана з будь-якого місця програми. Об'єктно-орієнтовне програмування (ООП) В даній парадигмі основою є певний об'єкт чи сукупність об'єктів, їхні властивості, методи і події. Власне з появою ООП і з'явилися такі терміни як клас, наслідування, поліморфізм, інкапсуляція. Якщо розглядати поняття об'єкту концептуально, то об'єкт є лише екземпляром певного класу об'єктів. Об'єкти представляють собою часткову інформацію про певну сутність, а власне певну модель, що адекватна завданню що треба вирішити. Цей варіант представлення називається абстракція даних. При такому представленні з об'єктом працювати набагато простіше, ніж з низькорівневим представленнями з описом всіх можливих властивостей і методів. Кожен об'єкт має свій певний тип (клас), що об'єднає в собі наступні елементи: Властивості – певні параметри і характеристики об'єкту Методи – дії, що можна виконувати над даним об'єктом, чи які може виконувати він сам Події – повідомлення що виникають при зміні стану об'єкта ООП функціонує за наступними принципами: Наслідування – це можливість породжувати один клас від іншого, при чому всі методи і властивості батьківського класу передаються дочірньому, дочірній клас в свою чергу може набувати нових методів і властивостей, яких не було в батьківському і також передавати їх в похідні від себе класи. Поліморфізм – це можливість дочірнього класу змінювати реалізацію тих чи інших дій батьківського класу. Інкапсуляція – це властивість об'єкта мати спеціальний інтерфейс (певний метод), через який і здійснюється взаємодія зовнішнього середовища з внутрішніми методами класу. При чому зовнішнє середовище може і не підозрювати про структуру і логіку внутрішніх методів. Якщо розглядати практичне застосування парадигм програмування стосовно PHP, то в попередніх до PHP 5 версіях використовується в основному процедурне програмування, так як об'єктна схема там вимальована достатньо умовно (тільки для виділення окремих сутностей, їх методів і властивостей в певні класи). Вже в 5-й версії PHP механізм взаємодії з об'єктами зазнав еволюційних змін. Вказівники (ссилки) і клонування Одною з базових змін є передача об'єкту як параметр функції по вказівнику а не по значенню, тобто всі функції, яким параметром передався об'єкт, працюють з одним і тим самим об'єктом, а не з його копіями. Це дозволяє уникати появи дублікатів об'єктів. Похідною від цього нововведення є вища продуктивність при обробці сценаріїв де активно використовуються об'єкти. Для створення копії об'єкта в PHP 5 використовується спеціальний метод __clone(). До цього методу неможна звернутись безпосередньо. Для безпосереднього використання використовується ключове слово clone. Розглянемо приклад використання цього методу в PHP 5: class SomeClass{ var $name; } // створюємо клас someObj1 і присвоюємо властивісті "name" значення "Object 1" $someObj1 = new SomeClass; $someObj1->name = 'Object 1'; // копіюємо клас someObj1 в someObj2 $someObj2 = clone $someObj1; echo $someObj1->name; // Виводить "Object 1" echo $someObj2->name; // Виводить "Object 1" // присвоюємо властивісті класу someObj2 "name" значення "Object 2" $someObj2->name = 'Object 2'; echo $someObj1->name; // Виводить "Object 1" echo $someObj2->name; // Виводить "Object 2" В PHP 4 для копіювання об'єкту замість $someObj2 = clone $someObj1 треба було б використати $someObj2 = $someObj1. На перший погляд все зручніше виглядало в PHP 4, але не будемо поспішати з висновками. Метод __clone() не обов'язково описувати (перезавантажувати) в класі. Але якщо ми це зробимо, то зможемо наперед задати поведінку об'єкта під час його клонування. Приклад: class SomeClass{ var $name; // перезавантаження методу __clone() function __clone() { $this->name = 'Copy'; } } // створюємо клас someObj1 і присвоюємо властивісті "name" значення "Original" $someObj1 = new SomeClass; $someObj1->name = 'Original'; // створюємо клас someObj2 // автоматично властивості "name" присвоюється значення "Copy" $someObj2 = clone $someObj1; echo $someObj1->name; // Виводить "Original" echo $someObj2->name; // Виводить "Copy" Області видимості методів і властивостей класів В PHP 5 введені специфікатори доступу до методів і властивостей класів: public – доступний без обмежень protected – тільки в середині класу, в якому вони оголошені і похідних від нього класах private – тільки в середині класу, в якому вони оголошені По замовчуванню виставляється тип доступу public. Розглянемо приклад з методами і властивостями різних типів доступності. // оголошуємо основний клас class SomeClass{ private $privateName = 'Private Name'; protected $protectedName = 'Protected Name'; public $publicName = 'Public Name'; private function PrivateFunction() { echo 'PrivateFunction()'; } protected function ProtectedFunction() { echo 'ProtectedFunction()'; } public function PublicFunction() { echo 'PublicFunction()'; } public function GetPrivate() { echo $this->privateName; } public function GetProtected() { echo $this->protectedName; } public function GetPublic() { echo $this->publicName; } } // оголошуємо похідний клас від SomeClass class SomeClass1 extends SomeClass { public function GetPrivateFromParent() { echo $this->privateName; } } $someObj1 = new SomeClass; $someObj2 = new SomeClass1; // Доступ до private методів і властивостей echo $someObj1->privateName; // Виводить помилку echo $someObj2->privateName; // Виводить помилку $someObj1->PrivateFunction(); // Виводить помилку $someObj2->PrivateFunction(); // Виводить помилку $someObj1->GetPrivate(); // Виводится 'Private Name' $someObj2->GetPrivate(); // Виводится 'Private Name'*/ $someObj2->GetPrivateFromParent(); // Нічого не виводиться // Доступ до protected методів і властивостей echo $someObj1->protectedName; // Виводить помилку echo $someObj2->protectedName; // Виводить помилку $someObj1->ProtectedFunction(); // Виводить помилку $someObj2->ProtectedFunction(); // Виводить помилку $someObj1->GetProtected(); // Виводится 'Protected Name' $someObj2->GetProtected(); // Виводится 'Protected Name' // Доступ до public методів і властивостей echo $someObj1->publicName; // Виводиться 'Public Name' echo $someObj2->publicName; // Виводиться 'Public Name' $someObj1->PublicFunction(); // Виводиться 'PublicFunction()' $someObj2->PublicFunction(); // Виводиться 'PublicFunction()' $someObj1->GetPublic(); // Виводиться 'Public Name' $someObj2->GetPublic(); // Виводиться 'Public Name' ?> Є ще також статичні (static) методи і властивості. Їхньою особливістю є те, що вони не належать певному об'єктові, вони єдині для цілого класу, і можуть викликатися без створення об'єкту. Зміна статичної властивості в одному з об'єктів класу призводить до його зміни для всіх об'єктів цього класу. Приклад: // оголошуємо основний клас class SomeClass{ static $staticVar = 'Static Variable'; static function StaticFunction() { echo 'StaticFunction()'; } } echo SomeClass::StaticFunction(); // Виводить StaticFunction() echo SomeClass::$staticVar; // Виводить Static Variable Константи класу При описі класу в PHP 5 можна задавати властивості-константи (ключове слово const). Викликати константи можна і без створення об'єкту на основі класу, в якому оголошені константи. Приклад: class SomeClass { const SOME_CONSTANT = "SOME CONSTANT"; } echo SomeClass::SOME_CONSTANT; // Виводить "SOME CONSTANT" Конструктори и деструктори Конструктор (__construct()) і деструктор (__destruct()) це методи що викликаються автоматично при створенні і знищенні об'єкту відповідно: class SomeClass{ function __construct() { echo 'Create object'; } function __destruct() { echo 'Destroy object'; } } $someObj = new SomeClass; // Виводиться Create object unset($someObj); // Виводиться Destroy object Абстрактні методи і класи. Абстрактні (abstract) методи і класи тільки оголошуються, клас який містить абстрактні методи повинен оголоситися як абстрактний. На основі абстрактного класу можна тільки створювати інші класи, а вже від них об'єкти. Абстрактний клас може містити і звичайні (не абстрактні) елементи. Приклад: abstract class SomeAbstractClass { // оголошення абстрактної функції abstract public function abstractFunction(); // оголошення неабстрактної функції public function GeneralFunction() { } } class SomeClass extends SomeAbstractClass { // перевантаження абстрактного методу public function abstractFunction() { echo 'abstractFunction()'; } } $someObj = new SomeAbstractClass; // Помилка створення об'єкта $someObj1 = new SomeClass; $someObj1->abstrFunc(); // Виводить 'abstractFunction()' Інтерфейси В PHP 5 немає множинного наслідування, тобто один клас не може бути створений на основі кількох інших класів. Але клас може бути створений на основі кількох інтерфейсів. Інтерфейс – це фактично абстрактний клас, який містить тільки абстрактні методи і не містить ніяких властивостей. Оголошуються інтерфейси з використанням ключового слова interface, а всі функції оголошуються стандартно, з використанням ключового слова function. Приклад: // оголошення інтерфейсів interface InterfaceOne { function SomeFunctionOne(); } interface InterfaceTwo { function SomeFunctionTwo(); } // оголошення класу на основі інтерфейсів class SomeClass implements InterfaceOne, InterfaceTwo { public function SomeFunctionOne() { echo 'SomeFunctionOne()'; } public function SomeFunctionTwo() { echo 'SomeFunctionTwo()'; } } $object = new SomeClass; $object->SomeFunctionOne(); // Виводить 'SomeFunctionOne()' $object->SomeFunctionTwo(); // Виводить 'SomeFunctionTwo()' Фінальні методи і класи В PHP 5 є можливість задати таку властивість класу і методу як фінальний (final). На основі фінальних класів неможливо створити класи нащадки. Також не можна перевизначити фінальний метод в класах нащадках. Приклад: final class FinalClass { } class ClassWithFinalMethod { final public function FinalFunction() { echo 'FinalFunction()'; } } // наступне оголошення класу викликає помилку class SomeClass1 extends FinalClass { // опис класу } // створюємо клас на основі класу з фінальним методом class SomeClass1 extends ClassWithFinalMethod { // наступне перевизначення методі викликає помилку public function FinalFunction() { } } Обробка винятків (помилок) Найцікавішим нововведенням в PHP 5 є методи для обробки винятків. Для цього використовуються конструкції try/catch/throw. Розглянемо простий приклад використання цих методів: try { // відкриваємо файл для читання $fp = @fopen("somefile.txt", "r"); // якщо файл відсутній, створюємо виключення if (!$someFile) throw new Exception(" Помилка відкриття файлу!"); fclose($someFile); } catch (Exception $exception) { // метод $exception->getLine() повертає номер рядка даного скрипта, в якому виникла помилка echo "Помилка в стрічці ", $exception->getLine(); echo $exception->getMessage(); // Выводит "Помилка відкриття файлу!" } Ключове слово instanceof Метод instanceof дозволяє визначити походження об'єкта, його приналежність до певного класу, або чи є він нащадком якогось об'єкта. Також за допомогою instanceof можна визначити чи об'єкт екземпляром класу, створеного на основі певного інтерфейсу. Приклад: interface SomeInterfaceOne { } interface SomeInterfaceTwo { } class SomeClassTypeOne { } class SomeClassTypeTwo extends SomeClassTypeOne {} class SomeClassTypeThree implements SomeInterfaceOne, SomeInterfaceTwo {} $objOne = new SomeClassTypeOne; $objTwo = new SomeClassTypeTwo; $objThree = new SomeClassTypeThree; $clonedObj = clone $objThree; // наступний блок виводить: об'єкт $objOne належить до класу SomeClassTypeOne if($objOne instanceof SomeClassTypeOne) echo 'об\'єкт $objOne належить до класу SomeClassTypeOne'; // наступний блок виводить: об'єкт $objTwo належить до класу SomeClassTypeTwo if($objTwo instanceof SomeClassTypeTwo) echo 'об\'єкт $objTwo належить до класу SomeClassTypeTwo'; // наступний блок виводить: об'єкт $objThree належить до класу SomeClassTypeThree if($objThree instanceof SomeClassTypeThree) echo 'об\'єкт $objThree належить до класу SomeClassTypeThree'; // наступний блок виводить: об'єкт $objTwo є екземпляром класу створеного на основі класу SomeClassTypeOne if($objTwo instanceof SomeClassTypeOne) echo 'об\'єкт $objTwo є екземпляром класу створеного на основі класу SomeClassTypeOne'; // наступний блок виводить: об'єкт $objThree є екземпляром класу створеного на основі інтерфейсу SomeInterfaceOne if($objThree instanceof SomeInterfaceOne) echo 'об\'єкт $objThree є екземпляром класу створеного на основі інтерфейсу SomeInterfaceOne'; // наступний блок виводить: об'єкт $objThree є екземпляром класу створеного на основі інтерфейсу SomeInterfaceTwo if($objThree instanceof SomeInterfaceTwo) echo 'об\'єкт $objThree є екземпляром класу створеного на основі інтерфейсу SomeInterfaceTwo'; // наступний блок виводить: об'єкта $clonedObj створений на основі об'єкту $objThree if($clonedObj instanceof $objThree) echo 'об\'єкта $clonedObj створений на основі об\'єкту $objThree'; Функція __autoload() Функція __autoload() викликається в випадку коли створюється об'єкт на основі неіснуючого класу Приклад: function __autoload($class) { echo "спроба створити об'єкт невизначеного класу ", $class; } // наступна стрічка виводить: // спроба створити об'єкт невизначеного класу MyClass // Fatal error: Class 'MyClass' not found in C:\wamp\www\test.php on line 5 $someObj = new SomeWrongClass; // наступна стрічка трохи практичніша // (екрануємо створення об'єту символом "@") // вона виводить: // спроба створити об'єкт невизначеного класу MyClass $someObj = @new SomeWrongClass; Перевантаження доступу до властивостей об'єкту Методи доступу __get() і __set() дозволяють динамічно визначати властивості об'єктів. __get() в якості параметра отримує ім'я властивості, а __set() окрім імені ще і нове значення властивості, яке відповідно і присвоює. Приклад: class SomeClass { private $classPropertys; function __set($name, $value) { echo "__set: присвоювання властивості $name = $value"; $this->classPropertys[$name]=$value; } function __get($name) { echo "__get: читання властивості $name: "; echo $this->classPropertys[$name]; } } $obj = new SomeClass; $obj->name = 'New Value'; // Виводить "__set: присвоювання властивості name=New Value" $value = $obj->name; // Виводить "__get: читання властивості name: New Value" Перевантаження викликів методів класу Якщо метод __call() описаний в певному класі, тоді він автоматично переловлює виклики до неіснуючих методів цього класу. В якості параметрів він отримує ім'я і параметри методу що викликається. Приклад: class SomeClass { function __call($name, $params) { echo "Помилка: викликано неіснуючий метод $name з параметром[ами]: "; foreach($params as $val) { echo $val.' | '; } } } $obj = new SomeClass; $obj->WrongMethodOne(1, 2, 'param'); // Виводить: 'Помилка: викликано неіснуючий метод WrongMethodOne з параметром[ами]: 1 | 2 | param |' $obj->WrongMethodTwo(123); // Виводить: 'Помилка: викликано неіснуючий метод WrongMethodOne з параметром[ами]: 123 |' |