ООП в PHP

Матеріал з Вікі ЦДУ
Перейти до: навігація, пошук

В програмуванні на PHP в основному використовуються такі парадигми програмування як процедурне і об'єктно-орієнтоване програмування.

Розглянемо ці парадигми детальніше.

Процедурне програмування.

Робота цієї концепції заснована на виклику так званих процедур (методи, функції, ...). Кожна процедура містить певну логіку для виконання тих чи інших операцій і може бути викликана з будь-якого місця програми.

Об'єктно-орієнтовне програмування (ООП).

В даній парадигмі основою є певний об'єкт чи сукупність об'єктів, їхні властивості, методи і події. Власне з появою ООП і з'явилися такі терміни як клас, наслідування, поліморфізм, інкапсуляція.

Якщо розглядати поняття об'єкту концептуально, то об'єкт є лише екземпляром певного класу об'єктів.

Об'єкти представляють собою часткову інформацію про певну сутність, а власне певну модель, що адекватна завданню що треба вирішити. Цей варіант представлення називається абстракція даних. При такому представленні з об'єктом працювати набагато простіше, ніж з низькорівневим представленнями з описом всіх можливих властивостей і методів.

Кожен об'єкт має свій певний тип (клас), що об'єднає в собі наступні елементи:

  1. Властивості – певні параметри і характеристики об'єкту
  2. Методи – дії, що можна виконувати над даним об'єктом, чи які може виконувати він сам
  3. Події – повідомлення що виникають при зміні стану об'єкта


ООП функціонує за наступними принципами:

  1. Наслідування – це можливість породжувати один клас від іншого, при чому всі методи і властивості батьківського класу передаються дочірньому, дочірній клас в свою чергу може набувати нових методів і властивостей, яких не було в батьківському і також передавати їх в похідні від себе класи.
  2. Поліморфізм – це можливість дочірнього класу змінювати реалізацію тих чи інших дій батьківського класу.
  3. Інкапсуляція – це властивість об'єкта мати спеціальний інтерфейс (певний метод), через який і здійснюється взаємодія зовнішнього середовища з внутрішніми методами класу. При чому зовнішнє середовище може і не підозрювати про структуру і логіку  внутрішніх методів.

Якщо розглядати практичне застосування парадигм програмування стосовно PHP, то в попередніх до PHP 5 версіях використовується в основному процедурне програмування, так як об'єктна схема там вимальована достатньо умовно (тільки для виділення окремих сутностей, їх методів і властивостей в певні класи). Вже в 5-й версії PHP механізм взаємодії з об'єктами зазнав еволюційних змін.


Області видимості методів і властивостей класів.

В PHP 5 введені специфікатори доступу до методів і властивостей класів:

   * public – доступний без обмежень
   * protected – тільки в середині класу, в якому вони оголошені і похідних від нього класах
   * private – тільки в середині класу, в якому вони оголошені


По замовчуванню виставляється тип доступу public.

Розглянемо приклад з методами і властивостями різних типів доступності.

   <?php
       // оголошуємо основний клас
   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) методи і властивості. Їхньою особливістю є те, що вони не належать певному об'єктові, вони єдині для цілого класу, і можуть викликатися без створення об'єкту. Зміна статичної властивості в одному з об'єктів класу призводить до його зміни для всіх об'єктів цього класу.

Приклад:

   <?php
     // оголошуємо основний клас
   class SomeClass
   {
       static $staticVar = 'Static Variable';

       static function StaticFunction()
       {
           echo 'StaticFunction()';
       }
   }
   echo SomeClass::StaticFunction(); // Виводить StaticFunction()
   echo SomeClass::$staticVar; // Виводить Static Variable
   ?>


Константи класу

При описі класу в PHP 5 можна задавати властивості-константи (ключове слово const). Викликати константи можна і без створення об'єкту на основі класу, в якому оголошені константи.

Приклад:

   <?php
   class SomeClass
   {
         const SOME_CONSTANT = "SOME CONSTANT";
   }
   echo SomeClass::SOME_CONSTANT; // Виводить "SOME CONSTANT"
   ?>


Конструктори и деструктори.

Конструктор (__construct()) і деструктор (__destruct()) це методи що викликаються автоматично при створенні і знищенні об'єкту відповідно:

   <?php
   class SomeClass
   {
       function __construct()
       {
           echo 'Create object';
       }

       function __destruct()
       {
           echo 'Destroy object';
       }
    }
   $someObj = new SomeClass; // Виводиться Create object
   unset($someObj); // Виводиться Destroy object
   
   ?>


Абстрактні методи і класи.

Абстрактні (abstract) методи і класи тільки оголошуються, клас який містить абстрактні методи повинен оголоситися як абстрактний. На основі абстрактного класу можна тільки створювати інші класи, а вже від них об'єкти. Абстрактний клас може містити і звичайні (не абстрактні) елементи.

Приклад:

   <?php
   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.

Приклад:

   <?php
   // оголошення інтерфейсів
   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). На основі фінальних класів неможливо створити класи нащадки. Також не можна перевизначити фінальний метод в класах нащадках.

Приклад:

   <?php
   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.

Розглянемо простий приклад використання цих методів: <?php

 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 можна визначити чи об'єкт екземпляром класу, створеного на основі певного інтерфейсу.

Приклад: <?php

 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() викликається в випадку коли створюється об'єкт на основі неіснуючого класу

Приклад: <?php

 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() окрім імені ще і нове значення властивості, яке відповідно і присвоює.

Приклад: <?php

 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() описаний в певному класі, тоді він автоматично переловлює виклики до неіснуючих методів цього класу. В якості параметрів він отримує ім'я і параметри методу що викликається.

Приклад: <?php

 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 |'

?>