Hlavní navigace

Na co si dát pozor při práci s objekty v PHP

Miroslav Holý

Cílem tohoto článku je upozornit na některé nezvyklé vlastnosti práce s objekty v PHP, jejich důsledky a možná řešení.

Uvedené skutečnosti vycházejí z práce s PHP verze 4.3.3.

Skrývání informací a implementace

Jedná se o jednu ze základních vlastností objektů. Ty mají být schopny navenek jednat prostřednictvím svého rozhraní a operace a atributy sloužící pouze jejich interní potřebě skrývat před okolím. PHP nedovoluje skrývat atributy a operace (private). V PHP jsou všechny atributy a operace veřejné! Možným řešením je využívat vlastních konvencí pro názvy operací a atributů, specifikaci zapsat do komentáře nebo použít dokumentační systém jako například Phpdocumentor. Phpdocumentor je obdoba Javadoc určená pro PHP. Dovoluje přiřadit operaci či atributu viditelnost. Pozor, údaje platí pouze pro dokumentaci, v rámci PHP je vše při starém.

Přiřazení

Přiřazení $objekt2=$objekt nepředá odkaz, ale hodnotu. PHP vlastně vytvoří nový objekt $objekt2 a do něj zkopíruje stav objektu $objekt. Nezbývá než používat konstrukce jako $objekt2=&$objekt, function &vratObjekt(), function (&$parametrOb­jekt) apod.

Identita objektu

Každý objekt má svůj vlastní jedinečný identifikátor (handle). Pro PHP je oním identifikátorem de facto název objektu (proměnné). V tomto ohledu PHP pracuje s objekty jako s primitivními typy. Ostatně jako při přiřazování. Chování PHP demonstruje následující ukázka.

Class A {
    var $a;
    function a() {
    $this->a=rand(0,100);
    }
    function getA() {
    return $this->a;
    }
}
$a=new A;
$b=&$a;
$a=new A;
echo $a->getA()."&#60br&#62";
echo $b->getA()."&#60br&#62";

Program vypíše vždy stejné hodnoty. Řešením je buď přiřadit hodnotu ($b=$a), nebo instanci třídy A podruhé nepojmenovat $a, ale zvolit jiné jméno. Uvedená vlastnost se nepříjemně projeví zejména při agregaci.

Class A {
    var $a;
    function a() {
    $this->a=rand(0,100);
    }
    function getA() {
    return $this->a;
    }
}

Class B {
    var $pole = array();
    function b() {
    for ($i=1;$i<=10;$i++) {
            $a=new A;
        array_push($this->pole,&$a);
        }
    }

    function nakresliB() {
    foreach ($this->pole as $a) {
    echo $a->getA()."&#60br&#62";
        }
    }
}

$b=new B;
$b->nakresliB();

Program vypíše stejné hodnoty. Nezbývá než vkládat do pole hodnoty místo odkazů, nebo nevytvářet při každém průchodu cyklu objekt s názvem $a, ale například objekt jako prvek pole $a, tedy $a[$i].

Délka života objektu

V PHP je životnost objektu spjata s během skriptu na webovém serveru. V praxi tedy objekt žije od kliknutí na odkaz uživatelem po zobrazení příslušné stránky na jeho prohlížeči. Naštěstí PHP umožňuje objekty serializovat a ukládat například do session proměnných. Tak můžeme pracovat s jedním objektem během celého sezení. Pro práci s objekty v rámci sezení lze využít následující konstrukce.

Nejdříve zjistíme, zda v session proměnné „a“ je příslušný objekt uložen. Pokud ne, vytvoří se nový, jinak se obnoví ze session proměnné.

if ($_SESSION['a']=="") {
        $a = new A;
} else {
        $a = $_SESSION['a'];

Na konci skriptu objekt $a uložíme zpět do session proměnné „a“.

$_SESSION['a']=$a;

PHP ukládá stav daného objektu i objektů, které jsou obsaženy v jeho proměnných nebo na které jeho proměnné ukazují. Je-li uložen objekt stádo skotu, který obsahuje pole krávy s prvky ukazujícími na jednotlivé objekty krav a pole býci, které obsahuje ve svých prvcích hodnoty objektů třídy býk, uloží se jak krávy, tak býci. Chování demonstruje následující příklad.

Class A {
    var $a;

    function a() {
    $this->a=rand(0,100);
    }

    function getA() {
    return $this->a;
    }
}

Class B {
    var $b;
    var $c;

    function b() {
        $a=new A;
    $this->b=$a;
    }

    function nakresliB() {
    echo $this->b->getA()."&#60br&#62";
    }

    function nakresliC() {
    echo "&#60br&#62".$this->c->getA()."&#60br&#62";
    }

    function setC(&$c) {
    $this->c=&$c;
    }
}

session_start();

if ($_SESSION['b']=="") {
    $b = new B;
    $c = new A;
    $b->setC($c);
} else {
    $b = $_SESSION['b'];
}
$b->nakresliB();
$b->nakresliC();
echo '&#60;br&#62;&#60;br&#62;&#60;a href="pokus.php"&#62;více&#60;/a&#62;';
$_SESSION['b']=$b;

Po každém kliknutí na odkaz „více“, který opět spustí uvedený skript pokus.php, se zobrazí stejný pár čísel.

Vícenásobná dědičnost

PHP nepodporuje vícenásobnou dědičnost ani nepovoluje vícenásobné dědění odpovědnosti, jako např. java pomocí „implements“.

Přetěžování

PHP nepodporuje přetěžování.

Abstraktní třídy

PHP nezná pojem abstraktní třídy, ale umí přepisování. To dovoluje definovat „abstraktní“ třídu jako běžnou třídu a v potomcích operace přepsat a naplnit je požadovaným obsahem.

Závěr

PHP vyžaduje od programátora jistou dávku disciplíny, a to zejména při kooperaci více lidí v rámci projektu. Práce s objekty v PHP má svá specifika, na která je třeba si zvyknout, nicméně nejsou zde překážky, které by objektově orientovanou tvorbu vysloveně komplikovaly.

Našli jste v článku chybu?
16. 5. 2005 10:10
uživatel si přál zůstat v anonymitě
nevim proc se mi tam ne jednou obevila tato stranka chci mit za domovskou stranku mit seznam tak mi to plosíííííím udelajte dekuji
17. 10. 2003 14:17
Jirka Hradil (neregistrovaný)

Tak ted nevim, co byste si presne predstavoval. Chcete primitivni datove typy? Tak je pouzivejte takove, jake jsou. Rad byste objekty? Mate je tam. Pokud chce zapouzdrit primitivni datovy typ, mate moznost. Pokud se vam nelibi pocitat s objektovou reprezentaci, tak si nestezujte, ze ji nemate. ;) Jestli mate konkretni navrh, jak udelat v tomto smeru zmenu v jazyku Java, poslete ji do Sunu s kopii na me, chytri panove v Sunu to jiste uvitaji. Muj nazor je takovy, ze soucasne reseni je to naprost…