A statikus metódusok és a $this
bullet Crystal -- 2009-05-27
PHP-ben van ugyan static kulcsszó, de ettől függetlenül a nem statikus metódusokat is meghívhatjuk statikusan. A legtöbben úgy tudják, hogy egy metódus belsejében annak alapján lehet eldönteni hogy statikus metódushívás történt-e vagy nem, hogy létezik-e a $this változó. Ez azonban sajnos nem mindig igaz.

Kicsit alaposabban körüljártam a dolgot, és írtam egy demót, letölthető innen. A demóban két osztály van, a B osztályban vizsgáljuk a $this-t, az A osztályból pedig B metódusát hívjuk. Nézzük, mit csinál az index.php:

A 7-8 sorban az index.php-ből hívjuk egy B típusú objektum metódusát, az eredmény nem meglepő, a $this B típusú objektum. Ezután a 11. sorban statikusan hívjuk B metódusát, itt a $this értéke NULL, ebben sincs semmi meglepő. A 14. sorban létrehozunk egy A típusú objektumot, a továbbiakban ezzel dolgozunk. Először A egy metódusából hívjuk B metódusát, itt a $this szintén B típusú, ez is magától értetődő.

Az érdekesség most jön. Az A objektum nem-statikusan hívott metódusából hívjuk B metódusát statikusan. Ekkor a B metódusában a $this egy A típusú objektum lesz - a hívó objektum, tehát a metódushívás környezete (!!).

Nem tudom hogy ez bug vagy feature, ha bug akkor ismert-e vagy nem, még nem jártam utána, de lehet hogy fogok. Elég durva, nehezen felderíthető hibák következhetnek ebből a viselkedésből.

Valószínűleg az történik, hogy a futtatókörnyezet metódushívásnál először a $this-t rakja rá a veremre, ha nem statikus a hívás. A metódus pedig innen veszi le a $this-t - vagy amit ott éppen talál - mikor szüksége van rá. Statikus híváskor persze nem kapják meg ezt a paramétert, és mikor szükség lenne rá, akkor leveszik a veremről amit ott éppen találnak. Ez most az A típusú hívó objektum. Ennek némileg ellentmond, hogy ha átadok A metódusának egy paramétert, akkor is az $a objektum lesz a B-ben a $this, pedig ez alapján a paraméternek kellene lenni. Nem tudom, hogy pontosan mi történik, 3 ötletem van:

* az interpreter leveszi az összes paramétert a veremről a metódushívás végén és átteszi máshova (miért tenné?)
* a $this változó nem első, hanem utolsó paraméterként adódik át, így a következő metódus a hívási listán azt találja a verem tetején. Ez se valószínű, az OO kódok nem így szoktak futni.
* a hívási listához tartozó $this objektumok külön veremben vannak, nem együtt a többi paraméterrel. Ez tűnik számomra a legvalószínűbbnek, bár ez is elég furcsa.

Majd ha jutottam valamire a dologgal akkor írok :)

Végül a teszt végén még A metódusát hívjuk statikusan, abból pedig B metódusát szintén statikusan, ilyenkor - nem meglepő - a $this értéke null lesz.
/* */ kommentek
firith (2009-05-28)
Ez érdekes, utánanézek a hétvégén. Szerintem a C-s kódokat kellene áttúrni, esetleg megnézni, milyen opcode keletkezik
Új komment:
név:
email:
website:

Captcha



megjegyzés