Forum und email

Nový Model Objektov

V PHP 5 je nový Model Objektov. Zaobchádzanie s objektami v PHP bolo kompletne prepísané, umožňujúc tak lepší výkon a viac vlastností. V predošlej verzii PHP boli objekty chápané ako primitívne typy (napr. integere a stringy). Nevýhodou tejto metódy bolo, že sa celý objekt sémanticky skopíroval pri priradení premennej alebo sa metóde poslala ako parameter. Po novom sú objekty odkazované cez handle a nie hodnotu (handle si môžete predstaviť ako idetifikátor objektu).

Mnoho PHP programátorv sa neobáva problému kopírovania starého modelu objektov, a preto väčšina PHP aplikácii bude fungovať mimo počítača alebo len s málo modifikáciami.

Tiež pozri direktívu zend.ze1_compatibility_mode pre kompatibilitu s PHP 4.

Členovia Private a Protected

PHP 5 predstavuje členské premenné private a protected, umožňujú vám definovať viditeľnosť vlastností triedy.

Example#1 Prístupnosť členov Private a Protected

K členskym premenným Protected sa dá pristupovať v triede rozširujúcej triedy, v ktorej sú deklarované, kdežto k členským premenným Private sa dá pristupovať iba cez triedu, ktorej patria.

<?php
class MyClass {
    private 
$Hello "Hello, World!\n";
    protected 
$Bar "Hello, Foo!\n";
    protected 
$Foo "Hello, Bar!\n";

    function 
printHello() {
        print 
"MyClass::printHello() " $this->Hello;
        print 
"MyClass::printHello() " $this->Bar;
        print 
"MyClass::printHello() " $this->Foo;
    }
}

class 
MyClass2 extends MyClass {
    protected 
$Foo;
              
    function 
printHello() {
        
MyClass::printHello();                          /* Malo by vypisat */
        
print "MyClass2::printHello() " $this->Hello/* Nemalo by vypisat nic */
        
print "MyClass2::printHello() " $this->Bar;   /* Nemalo by vypisat (nedeklarovane)*/
        
print "MyClass2::printHello() " $this->Foo;   /* Malo by vypisat */
    
}
}

$obj = new MyClass();
print 
$obj->Hello;  /* Nemalo by vypisat nic */
print $obj->Bar;    /* Nemalo by vypisat nic */
print $obj->Foo;    /* Nemalo by vypisat nic */
$obj->printHello(); /* Malo by vypisat */

$obj = new MyClass2();
print 
$obj->Hello;  /* Nemalo by vypisat nic */
print $obj->Bar;    /* Nemalo by vypisat nic */
print $obj->Foo;    /* Nemalo by vypisat nic */
$obj->printHello();
?>

Metódy Private a Protected

Spolu s PHP 5 boli predstavené aj metódy private a protected.

Example#2 Príklad metódy Protected

<?php
class Foo {
    private function 
aPrivateMethod() {
        echo 
"Foo::aPrivateMethod() called.\n";
    }

    protected function 
aProtectedMethod() {
        echo 
"Foo::aProtectedMethod() called.\n";
        
$this->aPrivateMethod();
    }
}

class 
Bar extends Foo {
    public function 
aPublicMethod() {
        echo 
"Bar::aPublicMethod() called.\n";
        
$this->aProtectedMethod();
    }
}

$o = new Bar;
$o->aPublicMethod();
?>

Starý kód, ktorý nemal žiadne užívateľom definované triedy alebo funkcie nazvané "public", "protected" alebo "private" by mal bežať bez modifikácii.

Triedy a Metódy Abstract

PHP 5 tiež predstavuje triedy a metódy abstract. Metóda abstract deklaruje iba signatúru metódy a neposkytuje implementáciu. Trieda, ktorá obsahuje metódy abstract musí byť deklarovaná ako abstract.

Example#3 Príklad triedy Abstract

<?php
abstract class AbstractClass {
    abstract public function 
test();
}

class 
ImplementedClass extends AbstractClass {
    public function 
test() {
        echo 
"ImplementedClass::test() volana.\n";
    }
}

$o = new ImplementedClass;
$o->test();
?>

Triedy Abstract nemôžu byť inštanciované. Starý kód, ktorý nemá žiadne užívateľom definované triedy alebo funkcie nazvané 'abstract' by mal bežať bez modifikácii.

Rozhrania

PHP 5 predstavuje rozhrania. Trieda môže implementovať ľubovoľný zoznam rozhraní.

Example#4 Príklad rozhrania

<?php
interface Throwable {
    public function 
getMessage();
}

class 
MyException implements Throwable {
    public function 
getMessage() {
        
// ...
    
}
}
?>

Starý kód, ktorý nemá žiadne užívateľom definované triedy alebo funkcie nazvané 'interface'alebo 'implements' by mal bežať bez modifikácii.

Typové Hinty triedy

PHP 5, stále voľne typové, predstavuje schopnosť použiť Typové hinty triedy na deklarovanie očakávanej triedy objektov, ktoré sú poslané metóde ako parametre.

Example#5 Príklad Typového hintu triedy

<?php
interface Foo {
    function 
a(Foo $foo);
}

interface 
Bar {
    function 
b(Bar $bar);
}

class 
FooBar implements FooBar {
    function 
a(Foo $foo) {
        
// ...
    
}

    function 
b(Bar $bar) {
        
// ...
    
}
}

$a = new FooBar;
$b = new FooBar;

$a->a($b);
$a->b($b);
?>

Teto typové hinty triedy sa nekontrolujú počas kompilácie, ako by to bolo v prípade typových jazykov, ale počas runtime. To znamená, že:

<?php
function foo(ClassName $object) {
    
// ...
}
?>

je zhodné s:

<?php
function foo($object) {
    if (!(
$object instanceof ClassName)) {
        die(
"Argument 1 musi byt instanciou ClassName");
    }
}
?>

final

PHP 5 predstavuje kľúčové slovo "final" na deklarovanie členov a metód final. Metódy a členovia deklarovavý ako final sa nemôžu preťažiť sub-triedami.

Example#6 Metóda final

<?php
class Foo {
    final function 
bar() {
        
// ...
    
}
}
?>

Ba čo viac, je možné vytvoriť triedy final. Toto zabraňuje triede byť špecializovanou (nemôže byť zdedená inou triedou). Nie je nutné samotné metódy triedy final deklarovať ako final.

Example#7 trieda final

<?php
final class Foo {
    
// definicia triedy
}

// nasledujuci riadok nie je mozny
// class Bork extends Foo {}
?>

Vlastnosti nemôžu byť final-ne.

Starý kód, ktorý nemal žiadne užívateľom definované triedy alebo funkcie nazvané 'final' by mal bežať bez modifikácii.

Klonovanie objektov

PHP 4 neponúkalo žiadny spôsob, akým by užívateľ mohol rozhodnúť, ktorý kopírovací conštruktor spustiť pri zdvojení objketu. Počas duplikácie, PHP 4 kopírovalo bit po bite tvoriac tak identickú repliku všetkých vlastností objektu.

Tvorba kópie objektu s plne replikovaými vlastnosťami nie je vždy žiadaným správaním. Dobrým príkladom potreby kopírovaích konštruktorov je, ak máte objekt, ktorý reprezentuje GTK okno a objekt drží zdroj tohto GTK okna, keď vytvárate duplikát, môžete chcieť vytvoriť nové okno s rovnakými vlastnosťami a mať nový objekt, ktorý drží zdroj nového okna. Ďalším príkladom je, ak váš objekt drží odkaz na ďalší objekt, ktorý on používa a keď replikujete rodičovský objekt, chcete vytvoriť novú inštanciu tohto druhého objektu, takže replika má svoju vlastnú oddelenú kópiu.

Kópia objektu je vytvorená pomocou kľúčového slova clone (ktoré volá, ak je to možné, metódu __clone() objektu). Metóda __clone() objetku sa nedá volať priamo.

Keď developer žiada vytvorenie novej kópiu objektu, PHP 5 skontroluje, či bola metóda __clone() definovaná alebo nie. Ak nie, zavolá východziu __clone(), ktorá skopíruje všetky vlastnosti objektu. Ak bola metóda __clone() definované, potom bude zodpovedná za nastavenie nutných vlastností vo vytvorenom objekte. Engine vhodne dodá funkciu, ktorá importuje všetky vlastnosti zo zdrojového objektu, takže môžu začať s by-value replikou zdrojového objektu a prelomiť vlastnosti, ktoré sa musia zmeniť.

Example#8 Klonovanie objektov

<?php
class MyCloneable {
    static 
$id 0;

    function 
MyCloneable() {
        
$this->id self::$id++;
    }

    function 
__clone() {
        
$this->address "New York";
        
$this->id self::$id++;
    }
}

$obj = new MyCloneable();

$obj->name "Hello";
$obj->address "Tel-Aviv";

print 
$obj->id "\n";

$obj_cloned = clone $obj;

print 
$obj_cloned->id "\n";
print 
$obj_cloned->name "\n";
print 
$obj_cloned->address "\n";
?>

Konštruktory

PHP 5 umožňuje developerom deklarovať metódy konštruktora pre triedy. Triedy, ktoré majú metódu konštruktora, volajú túto metódu pri každom novo-vytvorenom objekte, takže je vhodná pre akúkoľvek incializáciu, ktorú objekt môže potrebovať pred tým, než je je použitý.

V PHP 4 metódy konštruktora boli metódy triedy, ktoré mali rovnaký názov ako trieda samotná. Nakoľko je veľmi bežné volať rodičovský konštruktor z odvodených tried, spôsob, ako PHP 4 fungovalo, bol troška krkolomý na presúvanie tried vo veľkej hierarchii tried. Ak sa trieda presunula pod iného rodiča, názov konštruktora toho rodiča sa zmení tiež a kód v odvodenej triede, ktorá volá rodičovského konštruktora, sa tiež zmenil.

PHP 5 predstavuje štandardný spôsob deklarovania metód konštruktora ich volaním pomocou názvu __construct().

Example#9 Používanie novo unifikovaných konštruktorov

<?php
class BaseClass {
    function 
__construct() {
        print 
"Konstruktor v BaseClass\n";
    }
}

class 
SubClass extends BaseClass {
    function 
__construct() {
        
parent::__construct();
        print 
"Konstruktor v SubClass\n";
    }
}

$obj = new BaseClass();
$obj = new SubClass();
?>

Kvôli spätnej kompatibilite, ak PHP 5 nedokáte nájsť funkciu __construct() pre danú triedu, vyhľadá funkciu konštruktora starého štýlu, podľa názvu triedy. Z hľadiska efektivity to znamená, že jediný prípad, ktorý by mal problémy kompatibility je, ak trieda nemala metódu nazvanú __construct(), čo bolo použité pre odlišnú sémantiku.

Deštruktory

Mať schopnosť definovať deštruktory pre objekty môže byť veľmi užitočné. Deštruktory dokážu sledovať správy pre ladenie, zatvárať databázové spojenia a robiť iné čistiace práce. V PHP 4 neexistoval žiadny mechanizmus pre deštruktory objektov, i keď PHP už malo podporu pre registrovanie funkcii, ktoré sa malo spustiť pri požadovanom vypnutí.

PHP 5 predstavuje koncept deštruktorov podobný tomu v iných objektovo orientovaných jazykoch, ako je Java: Ak sa zničí posledný odkaz na objekt, zavolá sa deštruktor objektu, ktorý je metódou triedy nazvanou __destruct(), ktorá neprijíma žiadne parametre, pred tým, než sa objekt uvoľní z pamäte.

Example#10 Destructor

<?php
class MyDestructableClass {
    function 
__construct() {
        print 
"V konstruktore\n";
        
$this->name "MyDestructableClass";
    }

    function 
__destruct() {
        print 
"Destrukcia " $this->name "\n";
    }
}

$obj = new MyDestructableClass();
?>

Podobne ako konštruktory, rodičovské deštruktory nebudú volané implicitne engine-om. Aby sa pustil rodičovský deštruktor, musí sa explicitne zavolať parent::__destruct() v tele deštruktora.

Konštanty

PHP 5 predstavujes triedne konštanty:

Example#11 Príklad konštanty triedy

<?php
class Foo {
    const 
constant "constant";
}

echo 
"Foo::constant = " Foo::constant "\n";
?>

Starý kód, ktorý nemá žiadne užívateľom definované triedy alebo fukcie nazvané 'const' bude bežať bez modifikácii.

Výnimky

PHP 4 nemalo žiadne riadenie výnimiek. PHP 5 predstavuje model výnimiek podobný tomu v iných programovacích jazykoch. Pozor na fakt, že existuje podpora pre "catch all", ale nie pre klazulu "finally".

Výnimky sa dajú viackrát thrown-úť v catch blokoch. Tiež je možné mať viacnásobné catch bloky. V takom prípade sa zachytená výnimka porovná s typom triedy každého catch bloku od hora na dol a prvý blok, ktorý sa zhoduje s 'instanceof', sa spracuje. Keď sa catch blok ukončí, spracovanie pokračuje na konci posledného catch bloku. Ak sa žiadny catch blok nezhoduje s 'instanceof', potom sa hľadá ďalší try/catch blok až pokiaľ ďalšie try/catch bloky nie sú dostupné. V takom prípade je výnimka nezachytenou výnimkou a program sa ukončí zobrazením výnimky.

Example#12 Príklad tvorby výnimky

<?php
try {
   throw new 
Exception('Ahoj');
}
catch (
Exception $exception) {
   echo 
$exception;
}
?>

Starý kód, ktorý nemá žiadne užívateľom definované triedy alebo funkcie 'catch', 'throw' a 'try' bude bežať bez modifikácii.

Dereferencovanie objektov vratených z funkcií

V PHP 4 nebolo možné dereferencovať objekty vrátené funkciami a urobiť ďalšie volania metódy na tieto objekty. S PHP 5 je možné následujúce:

Example#13 Príklad dereferencie

<?php
class Circle {
    function 
draw() {
        print 
"Kruh\n";
    }
}
      
class 
Square {
    function 
draw() {
        print 
"Stvorec\n";
    }
}

function 
ShapeFactoryMethod($shape) {
    switch (
$shape) {
        case 
"Circle":
            return new 
Circle();
        case 
"Square":
            return new 
Square();
    }
}

ShapeFactoryMethod("Circle")->draw();
ShapeFactoryMethod("Square")->draw();
?>

Inicializácia premenných statických členov

Premenné statických členov statických tried sa môžu teraz inicializovať.

Example#14 Príklad inicializácie premennej Static

<?php
class foo {
    static 
$my_static 5;
    public 
$my_prop 'bla';
}

print 
foo::$my_static;
$obj = new foo;
print 
$obj->my_prop;
?>

Metódy Static

PHP 5 predstavuje kľúčové slovo 'static' na deklaráciu statický metód, teda volateľných mimo kontextu objektu.

Example#15 Príklad metód Static

<?php
class Foo {
    public static function 
aStaticMethod() {
        
// ...
    
}
}

Foo::aStaticMethod();
?>

Pseudo premenná $this nie je dostupná vo vnútri metódy, ktorá bola deklarovaná ako static.

instanceof

PHP 5 predstavuje kľúčové slovo instanceof, ktoré vám umožňuje zistiť, či objekt je alebo nie je inštanciou triedy, alebo či rozširuje triedu alebo implementuje rozhranie.

Example#16 Príklad instanceof

<?php
class baseClass { }

$a = new baseClass;

if (
$a instanceof baseClass) {
    echo 
"Hello World";
}
?>

Static function variables

Static-y sa teraz spracovávajú počas kompilácie, čo developer umožňuje priradiť premenné k static-om pomocou referencie. Táto zmena veľkolepo zlepšuje ich výkon, ale znamená, že nepriame odkazy na static-y nebude viac fungovať.

Parametre poslané referenciou

Parametre, ktoré sú poslané referenciou funkcii môžu teraz mať východzie hodnoty

<?php
function my_function(&$var null) {
    if (
$var === null) {
        die(
"$var musí mat hodnotu");
    }
}
?>

__autoload()

Zachytávacia funkcia __autoload() bude automaticky volaná, keď sa má nedeklarovaná trieda inštanciovať. Názov tejto triedy sa pošle zachytávacej funkcii __autoload() ako jej jediný argument.

Example#17 Príklad __autoload()

<?php
function __autoload($className) {
    include_once 
$className ".php";
}

$object = new ClassName;
?>

Preťažiteľné volania metód a prístupy vlastností

Obe, volania metód a prístupy vlastností sa dajú preťažiť cez metódy __call(), __get() a __set(). Tieto metódy budú spustené iba vtedy, keď vaše objekty neobsahujú vlastnost alebo metódu, ku ktorej sa snažíte dostať.

Example#18 __get() a __set()

<?php
class Setter {
    public 
$n;
    public 
$x = array("a" => 1"b" => 2"c" => 3);

    function 
__get($nm) {
        print 
"Ziskanie [$nm]\n";

        if (isset(
$this->x[$nm])) {
            
$r $this->x[$nm];
            print 
"Vratenie: $r\n";
            return 
$r;
        } else {
            print 
"Nic!\n";
        }
    }

    function 
__set($nm$val) {
        print 
"Nastavenie [$nm] na $val\n";

        if (isset(
$this->x[$nm])) {
            
$this->x[$nm] = $val;
            print 
"OK!\n";
        } else {
            print 
"Nie OK!\n";
        }
    }
}

$foo = new Setter();
$foo->1;
$foo->100;
$foo->a++;
$foo->z++;
var_dump($foo);
?>
Nastavenie [a] na 100
OK!
Ziskanie [a]
Vratenie: 100
Nastavenie [a] na 101
OK!
Ziskanie [z]
Nic!
Nastavenie [z] na 1
Nie OK!
object(Setter)#1 (2) {
  ["n"]=>
  int(1)
  ["x"]=>
  array(3) {
    ["a"]=>
    int(101)
    ["b"]=>
    int(2)
    ["c"]=>
    int(3)
  }
}

Example#19 Príklad __call()

<?php
class Caller {
    private 
$x = array(123);

    function 
__call($m$a) {
        print 
"Metoda $m volala:\n";
        
var_dump($a);
        return 
$this->x;
    }
}

$foo = new Caller();
$a $foo->test(1"2"3.4true);
var_dump($a);
?>

Iterácia

Objekty sa môžu iterovať spôsobom preťaženia, pri použití s foreach. Východzie správanie je iterovať cez všetky vlastnosti.

Example#20 Príklad iterácie objektu

<?php
class Foo {
    public 
$x 1;
    public 
$y 2;
}

$obj = new Foo;

foreach (
$obj as $prp_name => $prop_value) {
    
// pomocou vlastnosti
}
?>

Každá trieda, ktorej inštancie sa dajú iterovať s foreach by mala implementovať prázdne rozhranie Traversable. Teda každý objekt, ktorý hovorí, že implementuje Traversable sa môže použiť s foreach.

Rozhrania IteratorAggregate a Iterator vám umožňujú určiť ako sa objekty triedy iterujú v PHP kóde. Prvý z nich má metódu getIterator(), ktorá musí vrátiť pole alebo objekt, ktorý buď implementuje rozhranie Iterator alebo je inštaniciovaný z internej triedy, ktorá môže byť iterovaná

Example#21 Príklad tvorby Iterátora

<?php
class ObjectIterator implements Iterator {

    private 
$obj;
    private 
$num;

    function 
__construct($obj) {
        
$this->obj $obj;
    }
    function 
rewind() {
        
$this->num 0;
    }
    function 
valid() {
        return 
$this->num $this->obj->max;
    }
    function 
key() {
        return 
$this->num;
    }
    function 
current() {
        switch(
$this->num) {
            case 
0: return "1.";
            case 
1: return "2.";
            case 
2: return "3.";
            default: return 
$this->num.".";
        }
    }
    function 
next() {
        
$this->num++;
    }
}

class 
Object implements IteratorAggregate {

    public 
$max 3;

    function 
getIterator() {
        return new 
ObjectIterator($this);
    }
}

$obj = new Object;

// tento foreach ...
foreach($obj as $key => $val) {
    echo 
"$key = $val\n";
}

// sa zhoduje s nasledujucimi 7 riadkami s direktivou for.
$it $obj->getIterator();
for(
$it->rewind(); $it->valid(); $it->next()) {
    
$key $it->current();
       
$val $it->key();
          echo 
"$key = $val\n";
}
unset(
$it);
?>

Konštanta __METHOD__

Nová pseudo konštanta __METHOD__ ukazuje aktuálnu triedu a metódu, keď sa použije vo vnútri metódy a funkciu, keď sa použije mimo triedu.

Example#22 Príklad použitia __METHOD__

<?php
class Foo {
    function 
show() {
        echo 
__METHOD__;
    }
}

class 
Bar extends Foo {
}

Foo::show(); // posiela na vystup Foo::show
Bar::show(); // posiela na vystup Foo::show pretoze __METHOD__ je
             // token vyhodnoteny pocas kompilacie

function test() {
    echo 
__METHOD__;
}

test();      // posiela na vystup test
?>

Metóda __toString()

Nová zázračná metóda __toString() vám umožňuje preťažiť objekt na konverziu reťazca.

Example#23 Príklad __toString()

<?php
class Foo {
    function 
__toString() {
        return 
"Cokolvek";
    }
}

$obj = new Foo;

echo 
$obj// volaj __toString()
?>

Reflexné API

PHP 5 prichádza s kompletnou API reflexiou, ktorá pridáva schopnosť tvorbu-opančných tried, rozhraní, funkcíí a metód ronvako ako rozšírení.

Reflexné API tiež ponúkajú získanie doc komentárov pre funkcie, triedy a metódy.

Takmer všetky aspekty objektovo orientovaného kódu sa dajú reflektovať pomocou reflexného API, ktoré je » zdokumentované oddelene.

Example#24 Príklad použita reflexného API

<?php
class Foo {
    public 
$prop;
    function 
Func($name) {
        echo 
"Ahoj $name";
    }
}

reflectionClass::export('Foo');
reflectionObject::export(new Foo);
reflectionMethod::export('Foo''func');
reflectionProperty::export('Foo''prop');
reflectionExtension::export('standard');
?>