[PHP] Circular references vermijden

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Scyth
  • Registratie: Juli 2001
  • Laatst online: 16-03-2024

Scyth

Fat finger, three beer

Topicstarter
Voor een project móet ik de onderstaande opzet gebruiken:

Afbeeldingslocatie: http://www.scygen.com/web/ditmaardanzonderrarecircularreferenceszegmaar.jpg

En de sterk versimpelde aanroep:

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class baseClass {
  var $myArray;
  function __construct() {
    $this->myArray['subClass1'] = new subClass();
    $this->myArray['subClass2'] = new subClass();
  }
}

class subClass {
  var $parent;
  function func1() {
  }
  function func2() {
  }
}

$baseClass = new baseClass();


Ik ben nu echter al twee dagen on and off aan het prutsen hoe ik dit voor elkaar krijg zonder een circular reference te maken in de twee subclasses mbv. $parent.
$this->parent werkt niet, omdat de 'child' classes de baseClass niet extenden (ze extenden al een andere class namelijk). In principe kan de baseClass weggedacht worden; en dan ben ik op zoek naar een manier om de andere classes in de "myArray" aan te spreken.

Het zou mooi zijn als ik in de subClasses dit zou kunnen doen (psuedo)
code:
1
$this->parentArray['subClass2']->func2();

... dit werkt uiteraard niet. Iemand een idee?

Ik had wel een oplossing gevonden; maar ik weet niet in hoeverre deze oplossing 'netjes' is, en ik wil graag buiten het noemen van de baseClass om andere subClasses aanroepen.

PHP:
1
2
global $baseClass;
$baseClass->myArray['subClass1']->func1();


edit:

Het systeem draait op een PHP5.2 server, dus namespaces zijn niet toegestaan (PHP5.3+ als ik me niet vergis)

[ Voor 14% gewijzigd door Scyth op 26-03-2009 11:51 ]

Dell Studio XPS 16
Project: BavBierSub 1.0 BavBierSub 2.0


Acties:
  • 0 Henk 'm!

  • daniëlpunt
  • Registratie: Maart 2004
  • Niet online

daniëlpunt

monkey's gone to heaven

Ik denk dat het te maken heeft met deze 2 regels :
PHP:
1
2
$this->$myArray['subClass1'] = new subClass();
$this->$myArray['subClass2'] = new subClass();


Ik zou er dit van maken :
PHP:
1
2
$this->myArray['subClass1'] = new subClass(); 
$this->myArray['subClass2'] = new subClass();

Acties:
  • 0 Henk 'm!

  • Scyth
  • Registratie: Juli 2001
  • Laatst online: 16-03-2024

Scyth

Fat finger, three beer

Topicstarter
daniëlpunt schreef op donderdag 26 maart 2009 @ 11:45:
Ik denk dat het te maken heeft met deze 2 regels :
PHP:
1
enorme typo
Owja, nee sorry.. typo. Ik zal 'm veranderen.

[ Voor 34% gewijzigd door Scyth op 26-03-2009 11:51 ]

Dell Studio XPS 16
Project: BavBierSub 1.0 BavBierSub 2.0


Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

(jarig!)
Scyth schreef op donderdag 26 maart 2009 @ 11:40:
Ik ben nu echter al twee dagen on and off aan het prutsen hoe ik dit voor elkaar krijg zonder een circular reference te maken in de twee subclasses mbv. $parent.
En waarom moet dat precies? Je wilt vanuit de componenten van je overkoepelende klasse met de andere componenten kunnen communiceren oid? Maar je mag niet de makkelijkste weg er naar toe gebruiken??
Het systeem draait op een PHP5.2 server, dus namespaces zijn niet toegestaan (PHP5.3+ als ik me niet vergis)
Hoe zou je namespaces uberhaupt als oplossing van je probleem zien?

Overigens kan je vast we zoiets doen:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class baseclass
{
  private $subs;
  function __construct()
  {
    $this->subs = new subcontainer();
    $this->subs->add('sub1', new subclass($this->subs));
    $this->subs->add('sub2', new subclass($this->subs));
  }
}

class subclass
{
  private $subs;
  function __construct(subcontainer $subs){...}
}

class subcontainer
{
  private $sublist = array();
  function add($key, $sub)
  {
    $this->sublist[$key] = $sub;
  }
}


Je bent tenslotte niet verplicht ook echt een array direct te gebruiken lijkt me en met objecten kan je tenminste zonder geklooi met &'s de referenties doorgeven...

[ Voor 34% gewijzigd door ACM op 26-03-2009 12:06 ]


Acties:
  • 0 Henk 'm!

  • Scyth
  • Registratie: Juli 2001
  • Laatst online: 16-03-2024

Scyth

Fat finger, three beer

Topicstarter
ACM schreef op donderdag 26 maart 2009 @ 11:56:
En waarom moet dat precies? Je wilt vanuit de componenten van je overkoepelende klasse met de andere componenten kunnen communiceren oid? Maar je mag niet de makkelijkste weg er naar toe gebruiken??
Het probleem is dat de baseClass niet altijd geconstruct hoeft te worden in de variabele $baseClass.
$miep = new baseClass(); kan bijvoorbeeld ook.

Als je met de eenvoudigste manier dit bedoeld:
PHP:
1
2
3
4
function func1(){
  global $baseClass;
  $baseClass->myArray['subClass1']->func2();
}


moet ik 1. Voorkomen dat het als iets anders dan $baseClass geconstruct wordt, en
2. In elke functie van de subClass een global $baseClass zetten, met daaronder een gestoord lange aanroep(Ja, of ik moet een wrapper schrijven zoals dit:)

PHP:
1
2
3
4
5
6
class subClass {
  function call(<variabelen>){
    global $baseClass;
    $baseClass->myArray[....]->.... etc.
  }
}
ACM schreef op donderdag 26 maart 2009 @ 11:56:
Hoe zou je namespaces uberhaupt als oplossing van je probleem zien?
Ik meen ooit de constant __NAMESPACE__ te hebben gebruikt, en daar kwam dan de naam van de class baseClass uit. Ik kan me vergissen; wat hoogstwaarschijnlijk is. Ik dacht, ik nóem het even, voordat iemand met een oplossing komt in deze sferen. Die kan ik dan dus niet gebruiken.

Dell Studio XPS 16
Project: BavBierSub 1.0 BavBierSub 2.0


Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
Scyth schreef op donderdag 26 maart 2009 @ 11:40:
$this->parent werkt niet, omdat de 'child' classes de baseClass niet extenden (ze extenden al een andere class namelijk). In principe kan de baseClass weggedacht worden; en dan ben ik op zoek naar een manier om de andere classes in de "myArray" aan te spreken.
Sowieso gaat het dan om self::parent, maar goed...
Het zou mooi zijn als ik in de subClasses dit zou kunnen doen (psuedo)
code:
1
$this->parentArray['subClass2']->func2();

... dit werkt uiteraard niet. Iemand een idee?
Ik zou de instance van baseClass meenemen :)
Ik had wel een oplossing gevonden; maar ik weet niet in hoeverre deze oplossing 'netjes' is, en ik wil graag buiten het noemen van de baseClass om andere subClasses aanroepen.

PHP:
1
2
global $baseClass;
$baseClass->myArray['subClass1']->func1();
Dat zou ik eigenlijk helemaal niet doen. subClass hoeft namelijk niet te weten wie of wat die baseClass is. Het enige wat je moet hebben is dat hij het kan aanroepen:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Container{
  private $blocks;

  public function __construct(){
    $this->blocks[ 'block1' ] = new Block( $this );
    $this->blocks[ 'block2' ] = new Block( $this );
  }

  public function getBlock( $id ){
    if( array_key_exists( $id, $this->blocks ) ) return $this->blocks[ $id ];
    else throw new Exception( 'Block not found!' );
  }
}

class Block{
  private $container;

  public function construct( $container ){
    $this->container = $container;
  }

  public function foo(){
    return $something;
  }

  public function getFooFrom( $block ){
    $this->container->getBlock( $block ) ->foo();
  }
}
Hetzelfde als wat ACM ongeveer postte in zijn edit, alleen is de base gelijk je container. Ligt een beetje aan je ontwerpkeuze wat de beste optie is :)
Dat los je dus op met bovenstaande methode :)
[...]

Ik meen ooit de constant __NAMESPACE__ te hebben gebruikt, en daar kwam dan de naam van de class baseClass uit. Ik kan me vergissen; wat hoogstwaarschijnlijk is. Ik dacht, ik nóem het even, voordat iemand met een oplossing komt in deze sferen. Die kan ik dan dus niet gebruiken.
Je bedoelt __CLASS__. Dat is wat anders dan __NAMESPACE__. Die feature komt ook pas in 5.3 en het lijkt me sterk dat je met php5.3 aan het ontwikkelen bent :p

[ Voor 18% gewijzigd door mithras op 26-03-2009 12:12 ]


Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

(jarig!)
Scyth schreef op donderdag 26 maart 2009 @ 12:06:
Het probleem is dat de baseClass niet altijd geconstruct hoeft te worden in de variabele $baseClass.
$miep = new baseClass(); kan bijvoorbeeld ook.
Dat maakt toch ook niks uit?? Dat is dan ook mijn vraag niet, je wilt zo min mogelijk met global references. En als je met een OO aanpak bezig bent, zie ik geen goede reden - zeker in dit geval - niet om de boel ineens niet met OO te proberen op te lossen.

Je hebt het over circulaire referenties, maar ik zie in je vraag en/of voorbeelden eigenlijk niets dat op een echte circulaire referentie verwijst en ook nog eens geen reden waarom je dat zou willen voorkomen?

Je kan toch gewoon aan die subclass in zijn constructor een referentie naar ofwel de array/container ofwel de baseclass zelf meegeven?? ($sub = new sub($this);)
moet ik 1. Voorkomen dat het als iets anders dan $baseClass geconstruct wordt, en
2. In elke functie van de subClass een global $baseClass zetten, met daaronder een gestoord lange aanroep(Ja, of ik moet een wrapper schrijven zoals dit:)
Maar waarom moet de subclass uberhaupt de func2 van een andere subclass aan kunnen roepen?
Ik meen ooit de constant __NAMESPACE__ te hebben gebruikt, en daar kwam dan de naam van de class baseClass uit. Ik kan me vergissen; wat hoogstwaarschijnlijk is. Ik dacht, ik nóem het even, voordat iemand met een oplossing komt in deze sferen. Die kan ik dan dus niet gebruiken.
Nou, voor dat je daar mee aan de slag gaat moet je nog maar een keer goed lezen wat het doet, maar in ieder geval niet wat je nu verteld :P
mithras schreef op donderdag 26 maart 2009 @ 12:08:
Je bedoelt __CLASS__. Dat is wat anders dan __NAMESPACE__. Die feature komt ook pas in 5.3 en het lijkt me sterk dat je met php5.3 aan het ontwikkelen bent :p
__CLASS__ geeft ook niet de instancenaam, maar de classnaam van de functie waar de __CLASS__ geplaatst is (dus ook niet dynamisch voor subclassen vziw).

[ Voor 11% gewijzigd door ACM op 26-03-2009 12:13 ]


Acties:
  • 0 Henk 'm!

  • Scyth
  • Registratie: Juli 2001
  • Laatst online: 16-03-2024

Scyth

Fat finger, three beer

Topicstarter
Ik zal aan de slag gaan met de door jullie genoemde methoden. Ik zat wat in m'n maag met de recursie die bovenstaande methode tot gevolg heeft. In beide gevallen kan je nu iets in deze sferen doen:

$this->container->sub1->container->sub1->container->sub2->container->sub1->container->sub1->foo();

En precies dat wilde ik vermijden. Ik vind 't niet mooi, en volgens mij is het naast niet netjes ook nog 's raar voor PHP om te parsen. De oplossing zou eigenlijk heel simpel zijn als er een methode was om direct een reference naar de array te geven vanuit een object: getParentArray($this); ofzo. Dan zou 't al klaar zijn.

Bedankt heren, ik ga proberen jullie oplossingen implementeren.

Dell Studio XPS 16
Project: BavBierSub 1.0 BavBierSub 2.0


Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
ACM schreef op donderdag 26 maart 2009 @ 12:11:
[...]

__CLASS__ geeft ook niet de instancenaam, maar de classnaam van de functie waar de __CLASS__ geplaatst is (dus ook niet dynamisch voor subclassen vziw).
Ik meende uit deze opmerking:
Ik meen ooit de constant __NAMESPACE__ te hebben gebruikt, en daar kwam dan de naam van de class baseClass uit.
Hieruit op te maken dat hij dus in een klasse de naam van de klasse kreeg (en dus niet de instantie!). Dat doet __CLASS__.
Scyth schreef op donderdag 26 maart 2009 @ 12:19:
Ik zal aan de slag gaan met de door jullie genoemde methoden. Ik zat wat in m'n maag met de recursie die bovenstaande methode tot gevolg heeft. In beide gevallen kan je nu iets in deze sferen doen:

$this->container->sub1->container->sub1->container->sub2->container->sub1->container->sub1->foo();

En precies dat wilde ik vermijden. Ik vind 't niet mooi, en volgens mij is het naast niet netjes ook nog 's raar voor PHP om te parsen. De oplossing zou eigenlijk heel simpel zijn als er een methode was om direct een reference naar de array te geven vanuit een object: getParentArray($this); ofzo. Dan zou 't al klaar zijn.

Bedankt heren, ik ga proberen jullie oplossingen implementeren.
Het is geen recursie he! Het zijn references. Als je die blijft volgen kan je eeuwig in een cirkel ronddraaien, dat klopt. Maar daar is niets vreemds aan :)

Tegenwoordig gaat php te werken met 'pass by reference' (oid) ipv by intance. Dat voorkomt al jouw problemen en is in andere talen ook nou niet heel erg vreemd om zo te doen.

[ Voor 51% gewijzigd door mithras op 26-03-2009 12:22 ]


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

ACM schreef op donderdag 26 maart 2009 @ 12:11:
Je hebt het over circulaire referenties, maar ik zie in je vraag en/of voorbeelden eigenlijk niets dat op een echte circulaire referentie verwijst en ook nog eens geen reden waarom je dat zou willen voorkomen?
Wat is volgens jou dan een "echte" circulaire reference?

En een reden om ze te vermijden in PHP is omdat het een refcounting GC heeft. Met cyclische references worden je objecten nooit opgeruimd, omdat ze references naar elkaar in stand houden, ookal zijn er vanuit je programma geen references naar die objecten.
Scyth schreef op donderdag 26 maart 2009 @ 12:19:
En precies dat wilde ik vermijden. Ik vind 't niet mooi, en volgens mij is het naast niet netjes ook nog 's raar voor PHP om te parsen. De oplossing zou eigenlijk heel simpel zijn als er een methode was om direct een reference naar de array te geven vanuit een object: getParentArray($this); ofzo. Dan zou 't al klaar zijn.
Waarom zou dat volgens jou de oplossing zijn? Er is alsnog een reference naar de parent array, dus je kunt wederom de boel gaan herhalen:
$container->subs['sub1']->parentArray['sub1']->parentArray['sub1']->parentArray['sub1']->...

[ Voor 34% gewijzigd door .oisyn op 26-03-2009 12:33 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

(jarig!)
Scyth schreef op donderdag 26 maart 2009 @ 12:19:
Ik zal aan de slag gaan met de door jullie genoemde methoden. Ik zat wat in m'n maag met de recursie die bovenstaande methode tot gevolg heeft. In beide gevallen kan je nu iets in deze sferen doen:

$this->container->sub1->container->sub1->container->sub2->container->sub1->container->sub1->foo();
Dat het kan zegt toch niet dat je dat ook zo in je code gaat toepassen?? Uiteindelijk kan je natuurlijk via allerlei calls zoiets ook veroorzaken, maar dat voorkom je ook niet met jouw methodes.
Zolang je bij de andere sub's en hun functies wilt kunnen komen heb je gewoon dergelijke toegangspaden ontsloten.
En precies dat wilde ik vermijden. Ik vind 't niet mooi, en volgens mij is het naast niet netjes ook nog 's raar voor PHP om te parsen.
Als je dat letterlijk zo gaat zitten uitschrijven doe je iets hopeloos verkeerd. Zo'n sterke koppeling tussen de structuur van je precieze organisatie is bijzonder onverstandig. En volgens mij is bovenstaande ook nog eens te vervangen door gewoon direct $this->foo(); aan te roepen of als je niet met sub1 bezig bent dan zou je met $this->container->sub1->foo(); klaar moeten zijn.
De oplossing zou eigenlijk heel simpel zijn als er een methode was om direct een reference naar de array te geven vanuit een object: getParentArray($this); ofzo. Dan zou 't al klaar zijn.
Dat kan alleen als het subobject kennis heeft van het parent object, en die kennis moet je hem dan ook wel gewoon meegeven... Maar dan nog heb je nu nog geen verklaring gegeven waaruit ik met je eens bent dat je dat echt anders nodig hebt dan bijvoorbeeld mijn voorstel :)

Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

(jarig!)
.oisyn schreef op donderdag 26 maart 2009 @ 12:28:
Wat is volgens jou dan een "echte" circulaire reference?
Op het moment dat je referenties en overerving door elkaar gaat gebruiken (wat in de topicstart gebeurt) heb je het imho niet per se over circulaire reference ;) Uiteraard is zijn latere voorbeeld met de vele pijltjes wel circulair.
En een reden om ze te vermijden in PHP is omdat het een refcounting GC heeft. Met cyclische references worden je objecten nooit opgeruimd, omdat ze references naar elkaar in stand houden, ookal zijn er vanuit je programma geen references naar die objecten.
Wat vooral een probleem bij langlopende programma's is, de kans dat je objecten anders ruwweg even lang in leven zouden blijven als je scriptaanroep is vrij groot.

Acties:
  • 0 Henk 'm!

  • Scyth
  • Registratie: Juli 2001
  • Laatst online: 16-03-2024

Scyth

Fat finger, three beer

Topicstarter
ACM schreef op donderdag 26 maart 2009 @ 12:31:
Maar dan nog heb je nu nog geen verklaring gegeven waaruit ik met je eens bent dat je dat echt anders nodig hebt dan bijvoorbeeld mijn voorstel :)
Dat wat .oisyn zegt bedoel ik met circular references. Als de subclass een referentie heeft naar de parent class en de parent class weer naar de subclass via een $container variabele in de subclasses houden deze elkaar in stand. De PHP garbage collector heeft 't moeilijk dit op te ruimen omdat __destruct nooit aangeroepen wordt.
De reden waarom ik de topic opende was onderandere deze post: http://www.alexatnet.com/node/73
ACM schreef op donderdag 26 maart 2009 @ 12:33:
Wat vooral een probleem bij langlopende programma's is, de kans dat je objecten anders ruwweg even lang in leven zouden blijven als je scriptaanroep is vrij groot.
Dat is dan weer geen probleem; gedurende de hele scriptaanroep moeten de subClasses met elkaar kunnen communiceren.

[ Voor 22% gewijzigd door Scyth op 26-03-2009 12:40 ]

Dell Studio XPS 16
Project: BavBierSub 1.0 BavBierSub 2.0


Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier

(jarig!)
Scyth schreef op donderdag 26 maart 2009 @ 12:39:
Dat wat .oisyn zegt bedoel ik met circular references. Als de subclass een referentie heeft naar de parent class en de parent class weer naar de subclass via een $container variabele in de subclasses houden deze elkaar in stand. De PHP garbage collector heeft 't moeilijk dit op te ruimen omdat __destruct nooit aangeroepen wordt.
De reden waarom ik de topic opende was onderandere deze post: http://www.alexatnet.com/node/73
Dat is inderdaad een reden om er voorzichtig mee te zijn, maar tegelijkertijd ga je meestal niet continu opnieuw boompjes maken, maar maak je die slechts enkele malen en/of breid je hem uit.
Zodra je inderdaad veel objectboompjes maakt en die weer weggooit met dergelijke referenties, dan krijg je een probleem en moet je (zolang je niet met php5.3 bezig kan iig) kijken of je de circulaire referenties er uit kan halen.
Dat is dan weer geen probleem; gedurende de hele scriptaanroep moeten de subClasses met elkaar kunnen communiceren.
In dat geval zou ik voor de eenvoudige en efficiente aanpak gaan. Elk ander alternatief verplicht je namelijk om pas bij het nodig hebben van de parent een of andere relatief dure call te doen versus direct de reeds bekende referentie te volgen. :)

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Wat is er met 5.3 dan? Heeft die wel een volwaardige GC?

@Scyth: ik zou het trouwens "children" noemen ipv subclasses, omdat subclasses in OO een hele andere betekenis heeft (namelijk een class die van een andere class overerft)

[ Voor 60% gewijzigd door .oisyn op 26-03-2009 12:51 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • Scyth
  • Registratie: Juli 2001
  • Laatst online: 16-03-2024

Scyth

Fat finger, three beer

Topicstarter
.oisyn schreef op donderdag 26 maart 2009 @ 12:49:
Wat is er met 5.3 dan? Heeft die wel een volwaardige GC?
Dit in ieder geval:

The key features of the PHP 5.3 branch include:

• Support for namespaces
• Under the hood performance improvements
• Late static binding
[...]
• Optional garbage collection for cyclic references
[...]

Bron: http://www.php.net/archive/2009.php#id2009-03-24-1
.oisyn schreef op donderdag 26 maart 2009 @ 12:49:
@Scyth: ik zou het trouwens "children" noemen ipv subclasses, omdat subclasses in OO een hele andere betekenis heeft (namelijk een class die van een andere class overerft)
Het was een abstracte weergave van m'n classes. Ze heten hier anders, maar dit was duidelijker uitleggen. :>

Dell Studio XPS 16
Project: BavBierSub 1.0 BavBierSub 2.0


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Het is jammer dat het geen weak references kent, dat is vaak de gebruikelijke oplossing in een refcounting systeem.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1