function mymodule_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) { switch ($op) { case 'view': $obj = new myModuleNode($node); print $node->title; // print "Old title" $obj.changeNode(); print $obj->node->title; // print "New title" print $node->title; // print "New title" as well break; } } public class mymoduleNode() { public $node; function __construct($node) { $this->node = $node; } public changeNode() { // Change node $this->node->title = "New title"; } }
Összefoglalva: A class-ban ugyanazt az eredeti node-ot akarom változtatni, amit a hook függvényben is tettem.
Az lenne a kérdésem, hogy csináljam? Mi erre a szép megoldás?
Köszönöm
Drupal verzió:
Fórum:
Működik ez
Ennek így működnie kell, az egyetlen furcsaság, hogy . operátorral próbálsz hozzáférni az osztályod metódusához. Szóval azt cseréld le,
$obj.changeNode();
helyett$obj->changeNode();
legyen. Emiatt amúgy Fatal errort is kaptál, nem?Egyébként a kérdésed kapcsán elolvastam ChX remek bejegyzését a témában, nekem eléggé felnyitotta a szemem, hátha hasznos lesz neked/nektek is.
(Ja, és gondolom a Drupal verzió 6.x akart lenni, 7.x-nél már nincs
hook_nodeapi()
. :))Igen
d6 (elírtam)
Java kódban használtam objektumokat az utóbbi fél évben onnét jön a többi beidegződés. "Fatal errort is kaptál, nem?" - a fórum interpreter még csak egy warning-ot sem dobott. :)
erre nem kell az osztály
én csak visszakérdeznék:
igazából itt mi értelme van a
mymoduleNode
osztálynak? Mert annyi alapján, amit ez csinál, nem sok. Az egész igazából csak "zaj" a kódban, felesleges többlet.lehetne simán a hook_nodeapi-ban
$node->title = "új cím";
nem kell erre külön osztály, külön metódus, stb.
(Szerk.:) Az osztályban vétett hibákra Rimelek elég jól válaszolt.
Bálint:
szerintem a referencia megértéséhez a PHP manualja bőven elég lehet (lényegében a belinkelt tutorial azt mondja el másként, ami itt van):
http://php.net/manual/en/language.references.pass.php
:)
A $node->title átállítására
tényleg nem kell osztály, ez így van. :)
Ez a referencia dolog volt a kérdés.
Továbbadás szintén referenciaként
Nem csak az
$obj.changeNode()
a furcsa, hanem az osztály deklarálása is. Mert az osztály fejlécében nem kell a "kerek" zárójelet kitenni. Valamint az osztálynak PHP-ben a Java-val szemben nincsen láthatóság jelzője. Tehát csakclass MyModuleNode {
A changeNode elé pedig kell a function kulcsszó, nem úgy, mint java-ban.
De ezeket a nyilvánvalóan véletlen elírásokat leszámítva a kód jó úgy, ahogy van, ha a PHP 5 -öt használsz. Az objektumok ugyanis PHP 5 óta mindig referencia szerint adódnak át paraméterként is és értékadásnál sem készül róluk másolat.
Ha a $node változó nem objektum lenne, vagy a PHP 4-es verzióját használnád, akkor a megoldás a következő lenne:
Ahogyan a nodeapi hook is
&
jellel kapja meg a $node változót, úgy az osztály konstruktorának is úgy kellene azt várnia.public function __construct(&$node) {
Ez persze csak arra volna elég, hogy a konstruktorban ugyanazt a változót érd el, mint amit átadtál a konstruktornak. De ha továbbadnád tulajdonságnak, akkor ott is kellene használni a referenciajelölést.
Viszont mivel az objektumokat az ember többnyire nem másolgatni akarja, így azoknál nem szükséges a referenciajelölés. Ha mégis valami oknál fogva másolatot akarsz az objektumról, akkor a
clone
kulcsszót kell használnod.Így már egy másolaton dolgoznál. És pontosan ugyanazt az objektumot kapnád, mint az eredeti, csak más címen. Kivéve, ha változtatsz az adott osztály klónozásának működésén, de ebbe már nem megyek bele.
Tehát:
Ha egyszerre kellene neked az eredeti $node objektum és közben egy új is, akkor használnám a
clone
kulcsszót és másolnék. De nem ezt szeretnéd.Ha kizárólag az eredeti objektum módosítására kell az osztály, és az osztály konkrétan a node-hoz tartozik, tehát a modul egyéb funkcióiban nem játszik szerepet, akkor nem is használnék osztályt. Vagy ha több ilyen változtatás van, akkor statikus metódusokat használnák.
Ha pedig az eredeti, a drupal által stdClass-ba csomagolt node kiterjesztésére kell, és szintén más modulbeli műveleteket nem szolgál, akkor ilyesmit csinálnék:
A __get, __set, __isset, __unset metódusok miatt az értékadó és lekérdező műveletek, illetve az isset és unset műveletek is normál módon működnének. A nodeapi-ban pedig lecserélném a $node változót a sajátomra így:
$node = new myModuleNode($node);
És a drupal is úgy tud vele dolgozni, mint eredetileg, mert az eredeti node tulajdonságait éred el a kiterjesztetten keresztül. Viszont bővítheted saját metódusokkal, amiket felhasználhatsz. Ha kell, akkor vizsgálva, hogy milyen típusú a node.
Remélem, nem voltam túl bőbeszédű és nem néztem el valamit.
csak indokolt esetben érdemes!
+1-eztem a hsz.-t azért, mert PHP-lecke gyanánt szerintem tök jól jöhet PHP-ben kezdő OOP-seknek, DE azt azért tegyük hozzá - szerintem -, hogy csak NAGYON indokolt esetben érdemes ilyen osztályt írni, ha valaki tényleg tudja, mit csinál, és sok egyedi metódusra van szüksége, mert különben csak a kódbázis méretéhez, a futási időhöz és a memóriaigényhez tesz hozzá (még ha minimálisan is), jelentős valódi előnyök nélkül.
Egyetértek
Igen. Ezzel teljesen egyetértek.
Köszönöm
a választ. Ezt tényleg elég bőséges. Chx cikkét is megnézem majd.
Az objektumok ugyanis PHP 5
A mai napig ezt én is így fogalmaztam volna meg. ChX cikke azonban rávilágít, hogy ez nem így van, érdemes elolvasni.
bizony
Nem keverjük a handler és a resource paraméterátadást mert egy nap irtó pofáraesés lesz belőle. Így lehet a legremekebb, legnehezebben lenyomozható bugokat előállítani :D ha referenciával veszel át egy objektumot és bizonyos esetben a változónak más értéket adsz.
ezek nem ugyanazt csináják.
Ezek igen, viszont ástál magadnak egy szép kis vermet. Ne tegyünk tehát és jelet object változók elé.
Kétféle magyarázat
Kevésbé kockáknak: képzelj egy szép kis fiókos szekrényt, a fiókon a változó neve a címke, a fiókban meg a változó tartalma van. Egy PHP referencia pusztán egy újabb címke a fiókon. Az unset törli a címkét a fiókról, amelyik fióknak nincs több címkéje, az elérhetetlen, ezért a PHP szépen ki is dobja a tartalmát. A resource és object típusú változók a fiókban csak egy speciális bejegyzést tartalmaznak amin az áll "az én értékemet egy másik szekrényben (megfelelő resource vagy class) találod az X. számú fiókban". Ezért amikor átadjuk az ilyen változókat egy függvénynek akkor csupán lemásoljuk ezt a bejegyzést, nem csoda tehát hogy a függvényben a speciális szekrényben található értéket manipulálják. Ha referenciaként adjuk át akkor viszont lehetőség nyílik a fő szekrényben a bejegyzés kidobására és új bejegyzés készítésére.
Kockáknak: http://php.net/manual/en/internals2.variables.intro.php a PHP változók két részből állnak: egyrészt a változó neve ami szokás szerint a szimbólumtáblába kerül plusz egy mutató a változó tartalmára (ami egy zval struktúra). A
$a = &$b
után a és b ugyanarra a zval-ra mutat. A zval-ban van egy számláló (refcount) hogy hányan mutatnak rá, amikor ez nulla akkor eldobjuk. A tényleges változó érték egy zvalue_value union-ban van amire a zval-ban van egy pointer.Igazatok van
Igaz, igaz. A működést valójában ismerem, csak nem gondoltam bele a hibás megfogalmazásomba.
Ez a fiókos szekrény egy igen kedvelt szemléltető példa. Úgy látszik, ehhez már túl kocka vagyok, mert olvasás közben elvesztettem a fonalat. A kockáknak valóhoz meg nem vagyok elég kocka. Viszont a php.net-en az "Objects and references" pontban ez az első két bekezdés is. Szerintem elég lényegretörően megfogalmazza.