ugrás a tartalomhoz

PHP OOP, referencia, tömb (valamelyik ezek közül) probléma

PiG · 2005. Jún. 3. (P), 15.11
Sziasztok!

Akadt egy problémám, amit a következő kóddal próbálnék illusztrálni. Utána, ha addig eljuttok, a kérdéseim:

<?php
class Bolha{
	var $_nev;
	function Bolha($nev){$this->_nev=$nev;}
}//Bolha
class Kutya{
	var $_nev;
	var $_bolhak=array();
	var $_bolhaListazo;
	function Kutya($nev){
		$this->_nev=$nev;
		//+++++++++  1. hely +++++++++++++++
		$this->_bolhaListazo=new BolhaListazo();
		$this->_bolhaListazo->_kutya=&$this;
	}
	function ujBolha(&$bolha){if (is_object($bolha)) $this->_bolhak[]=&$bolha;}
	function bolhaLista(){
		//+++++++++  2. hely +++++++++++++++
		//$this->_bolhaListazo=new BolhaListazo();
		//$this->_bolhaListazo->_kutya=&$this;
		$this->_bolhaListazo->lista();
	}
}
class BolhaListazo{
	var $_kutya;
	var $_bolhak=array();
	function BolhaListazo(){}
	function lista(){
		echo $this->_kutya->_nev.'<br />';
		echo 'Bolhák száma: '.count($this->_kutya->_bolhak);
		$this->_bolhak=&$this->_kutya->_bolhak;
		foreach ($this->_bolhak as $bolha){
			echo $bolha->_nev;
		}
	}
}

$bloki=new Kutya('Blöki');
$bloki->ujBolha(new Bolha('Józsi'));
$bloki->ujBolha(new Bolha('Pisti'));
$bloki->ujBolha(new Bolha('Peti'));
$bloki->bolhaLista();
?>
Kérdéseim a következők:
ha az 1. hely-nél szerepel ez a kód:
$this->_bolhaListazo=new BolhaListazo();
$this->_bolhaListazo->_kutya=&$this;

akkor nem a kívánt eredményt kapom, azaz a bolhák száma 0 lesz és nem lesznek kilistázva a bolháim.
Ha ugyanez a két sor a 2. hely-en szerepel, akkor minden megy.
De bárhol szerepel az előbbi két sor, a echo $this->_kutya->_nev.'<br />'; mindig kiírja a kutya nevét, szóval az objektumreferencia megvan.
Szeretném valamilyen módon működővé tenni úgy, hogy a konstruktorban (1. hely) legyen az a két sor.
Ehhez kéne tanács!

P][G
 
1

PHP 4 bug/feature

bbalint · 2005. Jún. 4. (Szo), 11.48
úgy látszik, a $this nem akar olyan jól működni, mint kéne neki (se régebbi, se vadiúj PHP-val se – próbáltam: 4.3.3 és 4.3.11).
lehet a Zend baja, de Zend 2-ővel (PHP5) működött trendesen ...

bbalint
2

kis debug

bbalint · 2005. Jún. 4. (Szo), 11.57
ráadásul, a debug_zval_dump() függvény is azt mondja a $kutyára, hogy csak egy referencia van rá, tehát ...

az a sejtésem, hogy a $this csak ideiglenesen létezik, aztán mindenképp megszünteti a változót,

a PHP5 így jobban ojjektum-orientált, aztán a $this tényleg az aktuális objektumot jelenti.

bbalint
3

a miért

bbalint · 2005. Jún. 4. (Szo), 12.58
Zend kettőben nem "hack"ként van megoldva a $this, hanem külön van programozva:
PHP5 esetén van egy "globális" this (Execute Gloabls, EG(this)), amit mindig "frissít"
PHP4-ben "csak" egy $this változót hoz létre (és szüntet meg) a metódus-hívás elején/végén.

bbalint
4

recode

bbalint · 2005. Jún. 4. (Szo), 13.01
megírtam ugyanezt, viszont nem úgy, hogy a BolhaListazora, "ráerőszakolom" a kutyát, hanem a konstruktorának adom át:

<?php
 class állat{
  var $nev;
  
  function állat($nev){
   $this->nev = $nev;
  }
 }
 
 class bolha extends állat{
  function bolha($nev){
   $this->állat($nev);
  }
 }
 
 class ló extends állat{
  function ló($nev){
   $this->állat($nev);
  }
 }
 
 class bolhalistázó{
  var $kutyuli;
  
  function bolhalistázó(&$kutyuli){
   if(get_class($kutyuli) == 'kutyuli')
    $this->kutyuli =& $kutyuli;
   else
    print('Ő nem egy kutyuli, hanem egy \''.get_class($kutyuli).'\', te!<br/>');
  }
  
  function lista(){
   print('Kutyuli neve: '.$this->kutyuli->nev.'<br/>');
   
   if($this->kutyuli->bolhák){
    $bolhák = array();
    foreach($this->kutyuli->bolhák as $bolha)
     $bolhák[] = $bolha->nev;
    
    print('Ő bolhás, bolhái: '.implode(', ', $bolhák).'<hr/>');
   }else
    print('Ő nem bolhás<hr/>');
  }
 }
 
 class kutyuli extends állat{
  var $bolhák;
  var $bolhalistazo;
  
  function kutyuli($nev){
   $this->állat($nev);
   $this->bolhák = array();
   $this->bolhalistázó =& new bolhalistázó($this);
  }
  
  function bolha(&$bolha){
   if(get_class($bolha) == 'bolha')
    $this->bolhák[] =& $bolha;
   else
    print('Ő nem egy bolha, hanem egy \''.get_class($bolha).'\'!<br/>');
  }
  
  function bolhalista(){
   $this->bolhalistázó->lista();
  }
 }
 
 $Döme =& new kutyuli('Döme');
 $Döme->bolhalista();
 
 $Kincsem =& new ló('Kincsem');
 $Józsi =& new bolha('Józsi');
 $Pisti =& new bolha('Pisti');
 $Peti =& new bolha('Peti');
 
 $Bolhás =& new kutyuli('Bolhás');
 
 $Bolhás->bolha($Kincsem);
 $Bolhás->bolha($Józsi);
 $Bolhás->bolha($Pisti);
 $Bolhás->bolha($Peti);
 
 $Bolhás->bolhalista();
?>
így nekem szépen és jól működik:
Kutyuli neve: Döme
Ő nem bolhás
--
Ő nem egy bolha, hanem egy 'ló'!
Kutyuli neve: Bolhás
Ő bolhás, bolhái: Józsi, Pisti, Peti
--


bbalint
5

Köszi!

PiG · 2005. Jún. 4. (Szo), 18.40
Köszi a foglalkozást, a megoldást még tanulmányozom!
Egyébként azért még utánanéztem a dolognak, és több helyen írnak erről a viselkedésről, azaz a konstruktorban a $this-re való referencia létrehozásáról. Érdeklődőknek ajánlom! A probléma lényege:
... The answer lies in when the object was first created. In PHP 4, the new statement does not return a reference by default. Rather, when the $myvar object was created, it returned a copy separate from the one referenced by the $myref variable. Thus, because they are separate instances of the same object, their variables are completely independent. To overcome this and achieve the desired result, we use the reference-binding operator when creating the objects...

Tehát az általam írt kódban a
$bloki=new Kutya('Blöki');

erre írva:
$bloki=&new Kutya('Blöki');

már működőképes!
Egyébként, ha valakinél elérhető a PHP Anthology c. könyv, abban direkt ajánlják, hogy a new elé mindig tegyünk &-t (46. oldal)!
Let’s look at some other situations in which you might need to use references…

// Make sure $myObject is a reference to
// the variable created by the new keyword
$myObject = &new MyClass();


This looks odd at first, but remember, a variable created by the new keyword is being passed here—even if you can’t see it. The reference operator saves PHP from having to create a copy of the newly-created object to store in $myObject.

Ezek után úgy teszek!

P][G
6

kódolási stílus

bbalint · 2005. Jún. 4. (Szo), 22.01
hát, én nemt'om. én azért teszek és-jelet (ampershand) a new-nál, mivel a PHP manualba és PHP forráskódban úgy magyarázták ki, hogy amikor objektumot hozol létre és ad az ember értékül egy változónak:

<?php $változó = new StdClass(); ?>
a PHP4 először létrehoz egy StdClass objektumot majd annak értékét teszi bele a változóba, majd az objektumot megszünteti.

<?php $változó =& new StdClass(); ?>
ilyenkor pedig nem a létrejött objektum értékét, hanem az objektumra egy referenciát (magát az objektumot) teszi bele a változóba.

szóval, utóbbi változattal, memóriát, "időt" spórolok ezért használom.

bbalint
7

Na igen

PiG · 2005. Jún. 4. (Szo), 22.57
Hát ezek után már én is fogok...

P][G
11

nem stílus kérdése

Hodicska Gergely · 2005. Jún. 6. (H), 11.50
Egyszerűen a feladat szabja meg. Ha például a konstruktorban egy tömben eltárolod az elemet egy collection tagjaként (szülő tárolja a gyerekeit), akkor csak & alkalmazásával tudod elérni, hogy a tömbben tárolt, és a visszaadott objektum ugyanaz legyen. Plusz ilyen esetekben az is nagyon fontos, hogy ha van egy függvényed, amivel a szülőtől elkérhető a gyerek, akkor a definiciójána is legyen a függvénynév előtt &, különben az esetleges változtatások nem jelennek meg a szülő áltál tárolt verzióban.

Érdemes ezt a témát egyszer mindenkinek szépen lerendezni, kipróbálni a különböző lehetőségeket, mert ellenkező esetben nagyon aljas, nehezen debugolható hibákat vihetünk programjainkba.


Felhő
8

Újabb 'probléma'

PiG · 2005. Jún. 6. (H), 09.04
Sziasztok!

A bolhás példánál maradva:

<?php
class Bolha{
    var $_nev;
    function Bolha(){}
function setNev($nev){$this->_nev=$nev;}
}//Bolha
class Kutya{
    var $_bolhak=array();
    function Kutya(){}
    function ujBolha(&$bolha){$this->_bolhak[]=&$bolha;}
}//Kutya
$bloki=new Kutya();
for ($i=0;$i<5;$i++){
	$bolha=&new Bolha();
	$bolha->setNev('bolha_'.$i);
	$bloki->ujBolha($bolha);
}
?>
A gondom a következő:
function ujBolha(&$bolha){$this->_bolhak[]=&$bolha;}

Így adunk új bolhát a kutyához. Hogy elkerüljük az esetlegesen bazi nagy objektumok másolgatását, ezért referenciák szerepelne. bbalint is így írta :-)
Csakhogy a for ciklusban az értékadás nem fog működni, mivel a végén lesz 5 darab bolha_4 nevű kutyánk. (a kiíratást lespóroltam a kódbból, de így lesz). Ennek oka egyértelműen a referenciák használata.
Megoldás lenne, ha lenne a bolha objektum konstruktorában adnánk meg annak nevét is és így hajtanánk végre a ciklust:
for ($i=0;$i<5;$i++){
$bloki->ujBolha(new Bolha('bolha_'.$i));
}

Viszont előfordulhat, hogy a $bolha létrehozása után még egy csomó más tulajdonságát is be szeretnénk állítani. Ekkor nem tehetjük meg, hogy minden esetre felkészülve alkotjuk meg a konstruktor, mert az már átláthatlan lenne. Marad az, hogy nem használunk referenciát.
Így van, vagy valamit nagyon elnéztem?
(PHP 4.x)

P][G
9

ööö

bbalint · 2005. Jún. 6. (H), 10.04
hát, izé. nekem a fenti for(;;);-os kód rendesen bolha_0, bolha_1, bolha_2, bolha_4 és bolha_5 Bolhákat adogatja rá a Kutyára ...

ami talán (biztos) segítség, hogy a ciklusban nem egy változóba teszed bele az összes Bolhát, hanem egy "Bolhás" tömbbe:

<?php
  $bolhak = array();
  for($i = 0; $i < 5; ++$i){
    $bolhak[$i] =& new Bolha();
    $bolhak[$i]->setNev('bolha_'.$i);
    
    $bloki->ujBolha($bolhak[$i]);
  }
  // itt akár nyugodtan unset()ni is lehet a $bolhak változót; az elemeikre van rendesen két (vagy több) referencia is
?>
szóval, valami ilyesmi.

bbalint
10

Tömb - igen

PiG · 2005. Jún. 6. (H), 10.28
A tömbös megoldásra én is gondoltam.
A 'kutya-bolhásítás' csak egy leegyszerűsítése egy bonyolultabb problémának, ami nekem nem volt hajlandó működni. Mint írod, neked alapból működik a fenti kód. Úgy látszik az 'eredeti' kódban van még valahol máshol gubanc.
Egyébként köszi!

P][G