NightVision
Rugpjūtis 21, 2007

PHP 5 OOP

Prieš pradėdami skaityti straipsnį įsitikinkite, kad turite geras 4 Objektinio Programavimo žinias.
Straipsnyje bus naudojami tokie ženklai:

  • <> - tarp šių skliaustelių rašoma, kas turėtų būti toje vietoje;
  • <…> - ir taip toliau…
  • [] - tokie skliausteliai žymi, kad raktažodžiai nurodyti tarp šių skliaustelių nėra būtini;
  • | - nurodo, kad gali būti vienas ar kitas variantas.

Taip pat įsidėmėkite, kad metodai - tai klasių funkcijos.

Klasės, Klasės, Klasės….
Klasė tai kolekcija kintamųjų bei metodų, kuri sėkmingai gali dirbti su klasės kintamaisiais ir kitais metodais.

Pavyzdinė klasė parašyta 4 kalboje:

class Seima {
   // Keletas klasės kintamųjų
   var $Vaikai;
   var $Mama;
   var $Tetis;
 
   // Konstruktorius
   function Seima($Mama, $Tetis, $Vaikai) {
      // Priskiriame klasės kintamiesiems konstruktoriaus kintamųjų/argumentų reikšmes
      $this->Vaikai = $Vaikai;
      $this->Mama = $Mama;
      $this->Tetis = $Tetis;  
   }
 
   // Funkcija
   function ShowFamily() {
      echo "<PRE >";
      echo "Vaikai: ";
 
      // Spausdiname kintamąjį, kuris yra klasėje
      print_r($this->Vaikai);
      echo "\n";
 
      echo "Mama: {$this->Mama}\n";
      echo "Tetis: {$this->Tetis}\n";
      echo "</PRE >";
   }
}

Aukščiau pateiktos klasės objektą galime sukurti ir naudoti taip:

// Sukuriame klasę, jos objektą priskiriame kintamajam $Seima
$Seima  =& new Seima(
   "Mama1", "Tetis1",
   Array("Vaikas1", "Vaikas2", "Vaikas3")
);  
 
// Atvaizduojame šeimą
$Seima->ShowFamily();

Dabar susipažinkime su 5 Objektiniu Programavimu.
Visų pirma norėčiau paminėti, jog 5 kalboje norint perduoti objekto adresą nebereikia dėti adreso ženklo `&`.
Objekto Adresas 5 kalboje yra nusiunčiamas automatiškai.

Access modiferiai…. Kas tai?
Access modiferiai - tai klasėje esančio metodo ar kintamojo pasiekimo leidimas.
Access modiferiai 5 kalboje yra 3:

  • private - pasiekiamas TIK iš tos klasės, kur aprašytas;
  • protected - pasiekiamas iš tos klasės, kur aprašytas ir iš jos vaikų;
  • public - pasiekiamas iš visur.

Senąjį raktažodį var pakeičia naujasis 5 raktažodis public.
Jei 5 klasės metodui nenurodytas pasiekiamumas, jis automatiškai tampa public.
Todėl 5 gali tvarkytis su 4 klasėmis.

Metodų ir kintamųjų su access modiferiais aprašymo sintaksė:

[[final]|[abstract]] class <klasės pavadinimas> {
   [<access modiferis> $<kintamojo pavadinimas> [= <reikšmė>];]
   [<...>]
 
   [const <KONSTANTOS PAVADINIMAS> [= <reikšmė>];]
 
   [[<access modiferis>] [static] [[abstract]|[final]]
   function <funkcijos pavadinimas>(<argumentai>){<...>}|;]
 
   [<...>]
}

Klasės aprašymo ir panaudojimo pavyzdys:

class Foo {
   // kintamieji su įvairiais modiferiais
   public $Name;
   private $MyName;
   protected $Bar;
 
   // Konstruktorius.
   public function Foo($Vardas, $ManoVardas, $Baras) {
      // nustatome klasės kintamųjų reikšmes
      $this->Name = $Vardas;
      $this->MyName = $ManoVardas;
      $this->Bar = $Baras;
   }
 
   public function Reset() {
      // iškviečiame klasėje esančius metodus (klasės funkcijas)
      $this->SetBar("Hello");
      $this->SetMyName("Hi");
      $this->SetName("Bevardis");
   }
 
   public function Show() {
      return "{$this->Name}\n{$this->MyName}\n{$this->Bar}\n";
   }
 
   protected function SetBar($Reiksme) {
      // nustatome klasės kintamojo Bar reikšmę
      $this->Bar = $Reiksme;
   }
 
   private function SetMyName($Reiskme) {
      // nustatome klasės kintamojo MyName reikšmę
      $this->MyName = $Reiskme;
   }
 
   public function SetName($Reiskme) {
      // nustatome klasės kintamojo Name reikšmę
      $this->Name = $Reiksme;
   }
}
 
// Panaudojimo pavyzdys:
$FooClass = new Foo("Jonas", "Paulius", "Blynas");
echo $FooClass->Atvaizduoti(); // visi aukščiau nurodyti vardai bus sėkmingai atvaizduoti
echo "{$FooClass->Name}\n"; // ekrane pamatysime: "Jonas"
echo "{$FooClass->MyName}\n"; // Klaida! Negalima pasiekti "privataus" kintamojo.
echo "{$FooCloss->Bar}\n"; // Klaida! Negalima pasiekti "uždrausto" kintamojo
$FooClass->SetBar(10); // Klaida! Negalima pasiekti "uždrausto" metodo
$FooClass->Reset();
echo $FooClass->Show(); // sėkmingai išspausdins naujas reikšmes.
 
// Praplečiame klasę Foo (Sukuriame "vaiką")
class FooBar extends Foo {
   public function Show() {
      echo "Kita";
   }
 
   public function Debug() {
      $this->Reset(); // metodą įvykdys iš šios klasės (atspausdins "Kita")
      parent::Reset(); // metodą įvykdys iš paveldėtos klasės (Foo)
      $this->Show(); // metodą įvykdys iš parento.
      $this->SetBar("FooBar nustatytas."); // metodą įvykdys iš paveldėtos klasės sėkmingai
      $this->SetMyName("Dfsdasfasf"); // Klaida! Privatus metodas nepasiekiamas.
    }
}
 
// panaudojimo pvz.:
$FBObject = new FooBar();
$FBObject->Reset();
$FBObject->Show();
$FBObject->Debug();

Taigi kaip matome klasė FooBar taip pat įgijo paveldėtos klasės metodus ir kintamuosius.
Kitaip tariant praplėtė klasę Foo.

Naujas konstruktorius, ir DESTRUKTORIUS.
Konstruktorių galite vartoti kaip ir anksčiau (T.y. function <klasės pavadinimas>(<argumentai>) { <…> }).
Bet kam gi naudoti senąjį jei yra naujasis?
Naujojo konstruktoriaus pavadinimas - __constructor(…);
Konstruktorių aprašyti galime lygiai taip pat kaip ir anksčiau ( 4 kalboje) tik kitokiu pavadinimu.

Konstruktoriaus aprašymo sintaksė:

class <klasės pavadinimas> {
    public function __constructor([<Argumentai>][<...>]) {
        <...>
    }
}

Susipažinkime su destruktoriumi.
Destruktoriaus funkcija įvykdoma objekto sesijos pabaigoje (kai objektas yra nebenaudojamas).

Destruktoriaus aprašymo sintaksė:

class <klasės pavadinimas> {
   [public] function __destructor() {
      <...>
   }
}

Panagrinėkime konstruktoriaus ir destruktoriaus aprašymo ir naudojimo pavyzdį:

class Klase {
   public function __constructor($Argmentas, $Argumentas_2, $Argumentas_3 /* ..... */) {
      echo "Pradėta: {$Argumentas}, {$Argumentas_2}, {$Argumentas_3}....\n";
   }
 
   public function __destructor() {
      echo "Pabaigta\n";
   }
 
   public function DoSomething() {
      echo "Darau kažką...\n";
   }
}
 
// Panaudojimo pvz.:
$KlasesObj  =   new Klase("Vienas", "du", "trys");
$KlasesObj->DoSomething();
// ... //

Ekrane pamatysime:

Pradėta: Vienas, du, trys....
Darau kažką...
Pabaigta.

Turbūt kyla klausimas - kur aš galėčiau panaudoti tą “konstruktorių” ir “destruktorių”?
Atsakymas paprastas - tarkime duomenų bazės valdymui, kai reikia prisijungti prie duomenų bazės ir visų užklausų vykdymo pabaigoje reikia atsijungti nuo duomenų bazės.

Pavyzdžiui:

class DB_MySQL {
   protected $Database;
 
   public function __construct($Host, $Database, $Username, $Password) {
      $this->Database = mysql_connect($Host, $Username, $Password);
      mysql_select_db($Database);
   }
 
   public function __destruct() {
      mysql_close($this->Database);
   }
 
   public function SendQuery($Query) {
      return mysql_query($Query);
   }
}
 
$Localhost = new DB_MySQL("localhost", "mydatabase", "root", "sa");
$Result = $Localhost->SendQuery("SELECT * FROM Seeds");

Manau, jau supratote kaip veikia konstruktorius ir destruktorius.

Susipažinkime su Interfeisais (Angl. Interface)
Interfeisai - tai abstrakčių/deklaruotų metodų ir konstantų rinkinys.
Klasė, kuri paveldės interfeisą privalės aprašyti tuos metodus, kurie yra deklaruoti interfeise.
Interfeisai kaip ir klasės yra paveldimi panašiai tik naudojant raktažodį `implements`:

class <klasės Pavadinimas> implements <interfeisas>[,<...>] { }

Interfeisai yra aprašomi taip:

interface <interfeiso pavadinimas> {
   [const <KONSTANTOS PAVADINIMAS> [= <reikšmė>];]
 
   [<...>]
 
   [[<access modiferis>] [static] [[abstract]|[final]]
   function <funkcijos pavadinimas>(<argumentai>);]
 
   [<...>]
}

Kad interfeisų pavadinimai nesimaišytų su klasių pavadinimais, prie interfeiso pavadinimo rekomenduojama naudoti didžiąją `I` raidę:

interface I<interfeiso pavadinimas> {}

Interfeiso panaudojimo pavyzdys:

interface IFamily {
   const SEX_MALE = 0x00;
   const SEX_FEMALE = 0x01;
 
   public function __construct($Father, $Mother);
   public function AddChild($Sex, $Name);
}
 
class Family implements IFamily {
   private $Father;
   private $Mother;
   private $Childrens = Array();
 
   public function __construct($Father, $Mother) {
      $this->Father = $Father;
      $this->Mother = $Mother;
   }
 
   public function AddChild($Sex, $Name) {
      if($Sex == IFamily::SEX_MALE) // jei $Sex yra 0x00
         $this->Childrens['Male'][] = $Name;
      elseif($Sex == IFamily::SEX_FEMALE) // jei $Sex yra 0x01
         $this->Childrens['Female'][] = $Name;
      else // jeigu nebuvo nei 0x00 nei 0x01
         $this->Childrens['Unknown'][] = $Name;
   }
 
   public function Show() {
      echo "{$this->Father}'s & {$this->Mother}'s Family:\n";
      echo "   Father: {$this->Father}\n";
      echo "   Mother: {$this->Mother}\n";
      echo "   Childrens:\n";
 
      foreach($this->Childrens as $Sex => $Children)
         foreach($Children as $Name)
            echo "      {$Name} ({$Sex})\n";
   }
}
 
$Families = Array();
 
// Įkelia į masyvą objektą, kuris paveldi IFamily interfeisą
function AddFamily(IFamily $Family) {
   global $Families;
 
   $Families[] = $Family;
}
 
function ShowAll() {
   global $Families;
 
   echo "<PRE >";
 
   foreach($Families as $Family) {
      $Family->Show();
      echo "\n";
   }
 
   echo "</PRE >";
}
 
$TedFamily = new Family("Ted", "Lisa");
$TedFamily->AddChild(IFamily::SEX_MALE, "John");
$TedFamily->AddChild(IFamily::SEX_FEMALE, "Groove");
$TedFamily->AddChild(IFamily::SEX_FEMALE, "Rihana");
AddFamily($TedFamily);
 
$JohnFamily = new Family("John", "Britney");
$JohnFamily->AddChild(IFamily::SEX_MALE, "Gabriel");
$JohnFamily->AddChild(IFamily::SEX_FEMALE, "Garazi");
$JohnFamily->AddChild(IFamily::SEX_MALE, "Vandy");
AddFamily($JohnFamily);
 
ShowAll();

Ekrane pamatysime:

Ted's & Lisa's Family:
   Father: Ted
   Mother: Lisa
   Childrens:
      John (Male)
      Groove (Female)
      Rihana (Female)
 
John's & Britney's Family:
   Father: John
   Mother: Britney
   Childrens:
      Gabriel (Male)
      Vandy (Male)
      Garazi (Female)

5 kalboje yra galimybė deklaruoti abstraktų metodą ne tik interfeisuose bet ir klasėse - tai veikia lygiai taip pat.

Deklaruoti abstraktų metodą galime taip:

abstract <klasės pavadinimas> {
   [[<access modiferis>] [static] abstract function <funkcijos pavadinimas>(<argumentai>);]
}

Pavyzdžiui:

abstract class MyClass {
   public function DoSomething() {
      echo "I'm doing something...\n";
   }
 
   public abstract function DoWhatever();
}
 
$MyObject = new MyClass;
$MyObject->DoSomething(); // Metodą iškvies sėkmingai
$MyObject->DoWhatever(); // Klaida! Metodas DoWhatever yra abstraktus (neaprašytas)
 
class ExtendMyClass extends MyClass {
   public function DoWhatever() {
      echo "Hello!\n";
   }
}
 
$ExtendMyObject = new ExtendMyClass;
$ExtendMyObject->DoSomething(); // Metodą iškvies sėkmingai
$ExtendMyObject->DoWhatever(); // Metodą iškvies sėkmingai

Objektų klonavimas - kas tai?
Objektų klonavimas - tai objekto kopijavimas, o ne adreso gavimas.
Kaip minėjau 5 kalboje adresas objektams yra siunčiamas automatiškai,
todėl visada keisdami vieno kintamojo reikšmę (kuri yra objektas) pakeičiame ir kito kintamojo reikšmę.
Norėdami nepakeisti kito kintamojo reikšmės (objekto), o tiesiog sukurti naują objekto kopiją turime naudoti raktažodį `clone`.

Panagrinėkime vieną pavyzdį:

class Mano {
   public $Name;
 
   public function __construct($Name) {
      $this->Name = $Name;
   }
 
   // "Magiškasis metodas", kai objektas verčiamas į String tipą
   public function __toString() {
      return $this->Name;
   }
}
 
$Object = Array();
$Object[0] = new Mano("Jonas");
$Object[1] = new Mano("Petras");
 
echo "\$Object[0] = {$Object[0]}\n"; // $Object[0] = Jonas
echo "\$Object[1] = {$Object[1]}\n"; // $Object[1] = Petras
 
$Object[2] = $Object[0];
$Object[2]->Name = "Jonukas";
 
$Object[3] = $Object[1];
$Object[3]->Name = "Petriukas";
 
echo "\$Object[0] = {$Object[0]}\n"; // $Object[0] = Jonukas
echo "\$Object[1] = {$Object[1]}\n"; // $Object[1] = Petriukas
echo "\$Object[2] = {$Object[2]}\n"; // $Object[0] = Jonukas
echo "\$Object[3] = {$Object[3]}\n"; // $Object[1] = Petriukas

Kaip pastebėjote objektai pasikeitė tolygiai.

O dabar panagrinėkime sekantį pavyzdį, kai naudojame raktažodį `clone`:

class Mano {
   public $Name;
 
   public function __construct($Name) {
      $this->Name = $Name;
   }
 
   // "Magiškasis metodas", kai objektas verčiamas į String tipą
   public function __toString() {
      return $this->Name;
   }
}
 
$Object = Array();
$Object[0] = new Mano("Jonas");
$Object[1] = new Mano("Petras");
 
echo "\$Object[0] = {$Object[0]}\n"; // $Object[0] = Jonas
echo "\$Object[1] = {$Object[1]}\n"; // $Object[1] = Petras
 
$Object[2] = clone $Object[0];
$Object[2]->Name = "Jonukas";
 
$Object[3] = clone $Object[1];
$Object[3]->Name = "Petriukas";
 
echo "\$Object[0] = {$Object[0]}\n"; // $Object[0] = Jonas
echo "\$Object[1] = {$Object[1]}\n"; // $Object[1] = Petras
echo "\$Object[2] = {$Object[2]}\n"; // $Object[0] = Jonukas
echo "\$Object[3] = {$Object[3]}\n"; // $Object[1] = Petriukas

Manau, skirtumą pastebėjote iškart.

Susipažinkime su finalinėmis klasėmis ir metodais.
Finalinės klasės ir metodai (Angl. Final Classes & Methods) - tai tokios klasės, metodai, kurių praplėsti ar perrašyti (Angl. Override) negalima.
Final raktažodis tarsi užrakina metodą ar klasę.

Finalinės klasės ir metodai turi būti aprašyti taip:

final class <klasės pavadinimas> {
   [[<access modiferis>] [static] [final]
   function <funkcijos pavadinimas>(<argumentai>){<...>}]
 
   [<...>]
}

Panaudojimo pavyzdys:

final class MyFinalClass {
   public function function Do() {
      echo "Hello!\n";
   }
 
   public final function DoFinal() {
      echo "Hello Again!\n";
   }
}
 
// Klaida! Negalima paveldėti/praplėsti finalinės klasės!
class ExtendMyFinalClass extends MyFinalClass {
   // ...
}
 
class MyFinalMethod {
   public function function Do() {
      echo "Hello!\n";
   }
 
   public final function DoFinal() {
      echo "Hello Again!\n";
   }
}
 
// Gerai! Klasė nėra finalinė, todėl paveldėti/praplėsti galima
class ExtendMyFinalMethod extends MyFinalMethod {
   // Klaida! Negalima perrašyti finalinio metodo
   public function DoFinal() {
      // ...
   }
}

Turbūt pastebėjote, jei klasė yra finalinė, tai ir visi metodai, kintamieji bus taip pat finaliniai.

Panašūs straipsniai


“PHP 5 OOP” komentarų: 4

  1. adomas

    apie objektinį programavimą daug gerų resursų yra.. o kai žinai OOP tai nesvarbu ant ko OOP naudoti. naudingos čia nebent php plonybės kurias susigūglini kai prireikia. nu bet tarkim “zajebys pavarei” :D

  2. » PHP klausimai #2 - atsakymai Archyvas » Pixel.lt

    […] 3. Kas yra SimpleXML? SimpleXML - biblioteka (pateikiama kartu su PHP5), kurios pagalba galima lengvai ir patogiai dirbti su XML failais OOP būdu. […]

  3. PHP klausimai #5 » Pixel.lt

    […] 3.Kuo skiriasi PHP 4 ir PHP 5 konstruktoriai (oop)? […]

  4. PHP klausimai #5 (atsakymai) » Pixel.lt

    […] Kuo skiriasi PHP 4 ir PHP 5 konstruktoriai (oop)? PHP 4 konstruktoriaus pavadinimas yra identiškas klasės pavadinimui, o PHP 5 turi […]

Rašyti komentarą

Jūs privalote prisijungti jeigu norite rašyti komentarą.