PHP - ez miért működik?

Konkrétan, miért nem dob syntax errort rá? Semmi keresnivalója nincs a type hintingnek a szülőkonstruktor hívásánál - szerintem.

class ValamiClass extends ValamiOsClass
{
  public function __construct(AkarmiClass &$peldany);
  {
    parent::__construct(AkarmiClass &$peldany)
    
    // ...
  }
}

$valamiPeldany = new ValamiClass($akarmiPeldany);

Az oké, hogy dob egy " Cannot pass parameter 1 by reference" fatalt a parent::__construct() -nál, de egyáltalán miért kellene ennek átmennie a "fordítón"?

Hozzászólások

A fordító csak azt parzolja szemantikailag, ami éppen végrehajtódik/végrehajtódott.

Amikor definiálsz egy osztályt/függvényt, akkor csak azt nézi, hogy szintaktikailag helyes-e.

Nem, először befordítja a saját belső bináris kódjára (opcode), azután azt kezdi el végrehajtani. A Zend Optimalizer, eAccelerator és XCache pont arra játszik, hogy a már befordjtott opcode-t elmenti és azt tölti vissza ahelyett, hogy újra értelmezné a forráskódot (egész szép, akár 40-60%-t lehet hozni rajta).

De feltételezve, hogy neked lenne igazad, akkor is fennálna az, hogy miért nem dob egy ordas nagy syntax errort.

----------------
Lvl86 Troll

<?php
function bar() {
return foo();
}

function foo() {
return mt_rand();
}
?>
Ez teljesen valid, ha meghívom a bar() függvényt, akkor lefut, holott a foo() még nincs definiálva, amikor a bar() függvény parzolódik, és opcode lesz belőle (ezért mondtam azt, hogy nem csinál teljes szemantikai ellenőrzést).

PHP az egy PWTF nyelv... permanent WTF.
--


()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.

"A PHP az egy olyan nyelv, hogy random rácsapsz egy csomószor a billentyűzetre, és le fog fordulni PHP alatt, sőt még le is fut!"
"Minden nyelvben lehet randa kódot írni, de igazán gányolni csak PHP alatt lehet"
____________________________________
Az embert 2 éven át arra tanítják hogyan álljon meg a 2 lábán, és hogyan beszéljen... Aztán azt mondják neki: -"Ülj le és kuss legyen!"..

AkarmiClass definiálatlan (ez persze csak futáskor derül ki) konstans, így az 'AkarmiClass' stringet jelenti (deprecated feature, E_NOTICE jár érte; osztályok és konstansok független névtérben vannak, mivel nincs olyan hely, ahol mindkettőt lehetne használni). A & pedig itt a bitenkénti és művelet (persze konverziókkal hajtódna végre, amik közül az objektum->int konverzióért szintén E_NOTICE járna).

A "Cannot pass parameter 1 by reference" azt jelenti, hogy művelet eredményét nem lehet átadni referenciát váró függvénynek. Ha csak

parent::__construct(&$peldany)

lenne, az "PHP Warning: Call-time pass-by-reference has been deprecated" üzenetet eredményezne.

Szerk.: a szép, hogy a fatal error épp az előtt állítja le a programot, mint hogy a hiba okára utaló notice kijönne.

Az AkarmiClass elvileg definiált, de majd megnézem holnap. Valószínűleg neked lesz igazad, az E_NOTICE meg azért nem kerülhet ki az E_FATAL_ERROR előtt, mert egy saját error handler gyűjti a hibákat.

Viszont, ha nem definiált az az osztály, az felvet még egy érdekességet, mert épp egy olyan osztálypéldányt ad át, amikor ez hívódik a projektben. :)

----------------
Lvl86 Troll

Mint írtam, az osztályok és a konstansok névtere független. Ezen a helyen csak konstans szerepelhet, osztálynév nem, így az értelmező meg se nézi, hogy van-e ilyen nevű osztály; AkarmiClass nevű konstans pedig nincs.

Az értelmező először megnézi, hogy az AkarmiClass, &, $peldany tokenek sorban konstansnév (definiált vagy definiálatlan), "és" operátor és változónév; ezután jönne az operátor kiértékelése, itt venné észre, hogy a bal oldali operandusban lévő konstansnév nem definiált (tehát a nevét kell venni és notice-t dobni), és hogy az operandusokat konvetálni kell. De idáig már nem jut el, mert amikor észreveszi, hogy a paraméterben operátor van annak ellenére, hogy a függvény referenciát vár, fatal error-ral leáll.

Mar eleve ez a "osztályok és a konstansok névtere független" borzaszto, de a legborzasztobb, hogy egyaltalan nem syntax error-ral szall el. Vagy legyen az, hogy a konstruktor kaphat akarmit, type hintinggel, vagy a konstruktor ne kaphasson parametert, es szalljon el itt az egesz syntax error-ral. Ez... nos ez igy ahogy leirtad, valami eszement dolog.
--


()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.

"Mar eleve ez a "osztályok és a konstansok névtere független" borzaszto"

Miért? Adott helyen csak az egyik lehet, úgyhogy nem lehet ütközés.

"a legborzasztobb, hogy egyaltalan nem syntax error-ral szall el"

Mitől lenne syntax error? Ez egy sima logikai és művelet, aminek a bal oldalán konstans áll. A környezetből egyértelmű, hogy itt osztálynév nem állhat, és metódushívásnál fel sem merül, hogy type hinting lenne.

Szerk.: Ha nem lehetne egyező konstans- és osztálynév, akkor se lehetne parser (syntax) error, mert amikor ezt a kódot értelmezi az értelmező, akkor még azt se biztos, hogy tudja, hogy ilyen néven osztály vagy konstans lesz. Ilyenkor most feltételezi, hogy konstansnév, mert más nem lehet.

Valamit nem ertetel meg. Egy konstruktorban a leggjobb esetben is csak osztalynev es valtozonev allhat egy objektumorientalt nyelvben, mas nem. Tehat, ha egy olyan tokenhez erunk, ami osztalynev (mert ugye konstans... egy konstruktor deklaracioban...), de ilyen osztaly nincs, akkor az parser error, mert ismeretlen osztaly. Ez a javatol a c++-on at a ruby-ig igy mukodik.

Mar az eleve oriasi baki, hogy egy _fuggvenydeklaracio_ parsolasa eseten a PHP-ban eloallhat olyan eset, hogy valami logikai muveletet akar elovenni. Egy fuggvenydeklaracioban ilyesminek nincs helye, az interpreter nem akarhat ilyesmit beleerteni a kodba (nem mintha lenne egyaltalan a dolognak valamilyen ertelme).

Tehat itt igenis parser/syntax errornak kellene kovetkeznie. Mindenkeppen. Amit mondasz, az lehet hogy igaz, de ettol meg nagyon kozel all a keptelenseghez.
--


()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.
parent::__construct(AkarmiClass &$peldany)

Ez nem egy függvénydeklaráció, hanem egy metódushívás. Aminek a paramétere miért ne lehetne egy logikai kifejezés? Másrészt egy metódushívás paraméterlistájában nem lehet osztálynév (csak :: előtt), globális konstans viszont lehet.

En azt hittem, errol beszelgetunk:


public function __construct(AkarmiClass &$peldany);

Ebben nagyon hulyen nez ki amit mondtal. Viszont ha a masik kodrol van szo... nos ott is hulyen nez ki, csak nem annyira.
Kulonben, ha a nyelv tamogat olyant, hogy castolas, akkor igenis elofordulhat egy metodushivas parameterlistajaban osztalynev. Persze a PHP nem igazan tipusos nyelv.
--


()=() Ki oda vagyik,
('Y') hol szall a galamb
C . C elszalasztja a
()_() kincset itt alant.

Jé, most veszem észre a
[code]public function __construct(AkarmiClass &$peldany);[code]
végén a pontosvesszőt, ami miatt persze nem is működik - gondolom, kézzel lett beírva a kód.

Amúgy viszont ez a deklaráció rendben van, mint type hinting, itt persze osztálynév az AkarmiClass. A probléma a parent::__construct() hívással volt, ahol type hintinget próbáltak rakni a függvényhívásba, a PHP meg persze nem annak értelmezte.

"ha a nyelv tamogat olyant, hogy castolas, akkor igenis elofordulhat egy metodushivas parameterlistajaban osztalynev."

Valóban, de (a C/C++/PHP typecast operátorával) akkor se ilyen módon lenne, hanem zárójelben.

Hopsz, ott a pontosvessző véletlen került bele a hupos blogbejegyzésbe.

"A probléma a parent::__construct() hívással volt, ahol type hintinget próbáltak rakni a függvényhívásba, a PHP meg persze nem annak értelmezte."

Igazából nem akart senki ott type hintinget és/vagy castolást, szimplán át lett adva az összes paraméter az őskonstruktornak, mert annak kellett minden és erre gondolom a leggyorsabb megoldás az volt, hogy a definíció paraméterezését CTRL+C,V-zni és valószínűleg így maradt benn a definíció type hintingje.

----------------
Lvl86 Troll