Door
Wilfred Dijksman
op 30-01-2013 22:30
gewijzigd op 30-01-2013 22:31
2.414 views
Hi PHP-hulpers,
Ik heb een parent class die doormiddel van een private methode een andere child class aanmaakt. De child class extends de parent class.
Vervolgens voer ik in de child class een methode uit die gedefineerd wordt in de parent class. In die methode wordt een property gebruikt uit de parent class die in de __construct van de parent class wordt ingesteld op: $this->ch = curl_init();
Eerder genoemde methode (gedefineerd in de parent class) gebruikt $this->ch voor het uitvoeren van een aantal curl_exec's. Wanneer ik de methode echter probeer uit te voeren krijg ik de foutmelding dat $this->ch = NULL en dus !niet een resource voor curl is. Dit blijkt ook wanneer ik in de child class var_dump($this->ch); uitvoer.
Hoe kan ik de methode uit de parent class toch gewoon gebruiken in de child class?
parent::__construct uitvoeren in de child class is geen optie. Via een andere methode die in de __construct van de parent class wordt aangeroepen wordt namelijk de child class geladen. Oftewel, de child class wordt dan een tweede keer geïnitialiseerd en die ïnitialiseerd de child class weer enz., enz.
De $this->ch in de child class pas instellen op $this->ch = curl kan ook niet omdat in de parent class $this->ch al nodig is en $this->ch in de child class met deze curl_session moet draaien.
Hieronder nog even een (vereenvoudigde) weergave ter verduidelijking:
[size=120]parent.class.php[/size]
<?php
class Parent{
protected $ch;
function __construct(){
$this->ch = curl_init();
loadClass();
}
private function loadClass(){
include('apps/'.$_GET['app'].'/lib/class.php');
return new $_GET['app'];
}
public function curlGet($url){
curl_setop($this->ch, CURLOPT_URL, $url); // error child.class.php verwijs naar deze lijn
curl_setop($this->ch, CURLOPT_RETURNTRANSFER, true); // error child.class.php verwijs naar deze lijn
return(curl_exec($this->ch));
}
}
?>
[size=120]child.class.php[/size]
<?php
class Child extends Parent{
function __construct(){
curlGet($url); // error: PHP Warning: curl_setopt() expects parameter 1 to be resource, null given in Parent.class.php on line 16 & 17
}
}
?>
Ik hoop dat iemand me met bovenstaande vraag kan helpen.
Alvast bedankt voor jullie hulp en tijd, Wilfred Dijksman
(Ik heb niet alles grondig gelezen, misschien ontgaat me iets aan deze discussie)
Ik vrees dat ik weeral zal moeten spreken vanuit mijn C achtergrond.
Ik vind dat elke class best een constructor kan hebben.
Ik vind dat elke extend best een eigen constructor kan hebben.
Normaal zou ik daar nooit over zagen/klagen, maar in dit topic is het relevant.
Jij zou in je parent class een methode init() kunnen schrijven; waar je regelt wat echt moet geregeld worden. $this->init() wordt uitgevoerd in de constructor.
Dan kan je in de child die init aanspreken; laat je de constructor van de parent met rust. Geen verwarring, geen conflict, geen probleem meer.
Ja, het is een systeem wat meerdere modules/apps heeft die wel dezelfde basis functies nodig hebben. Die basis functies zitten in de parent class.
[size=xsmall]Toevoeging op 31/01/2013 15:10:14:[/size]
Ik heb ondertussen een oplossing voor mijn probleem:
Ik laad een variabele met daarin het parent class object in de child class zodat via die variabele alles toegankelijk is vanuit de child class. Zie ook het voorbeeld hieronder:
parent.class.php
<?php
class Parent{
private $app;
function __construct(){
loadChild($var);
}
function loadChild($nameClass){
include('lib/'.$nameClass.'.class.php');
$this->app = new $nameClass($this);
}
function getSomething($what){
return($what);
}
}
?>
child.class.php
<?php
class Child{
private $parent_object;
function __construct($parent_object){
$this->parent_object = $parent_object;
// execute methode from Parent class
$this->parent_object->getSomeThing();
}
}
?>
Opmerking: Nadeel van deze methode is natuurlijk wel dat de visability van properties en methodes omzeilt wordt.
Mochten jullie nog opmerkingen / andere suggesties hebben dan hoor ik dat graag. Nogmaals dankt voor jullie meedenken tot zover.
Met vriendelijke groet, Wilfred Dijksman
[size=xsmall]Toevoeging op 31/01/2013 15:15:22:[/size]
Ja, het is een systeem wat meerdere modules/apps heeft die wel dezelfde basis functies nodig hebben. Die basis functies zitten in de parent class.
[size=xsmall]Toevoeging op 31/01/2013 15:10:14:[/size]
Ik heb ondertussen een oplossing voor mijn probleem:
Ik laad een variabele met daarin het parent class object in de child class zodat via die variabele alles toegankelijk is vanuit de child class. Zie ook het voorbeeld hieronder:
parent.class.php
<?php
class Parent{
private $app;
function __construct(){
loadChild($var);
}
function loadChild($nameClass){
include('lib/'.$nameClass.'.class.php');
$this->app = new $nameClass($this);
}
function getSomething($what){
return($what);
}
}
?>
child.class.php
<?php
class Child{
private $parent_object;
function __construct($parent_object){
$this->parent_object = $parent_object;
// execute methode from Parent class
$this->parent_object->getSomeThing();
}
}
?>
Opmerking: Nadeel van deze methode is natuurlijk wel dat de visability van properties en methodes omzeilt wordt.
Mochten jullie nog opmerkingen / andere suggesties hebben dan hoor ik dat graag. Nogmaals dankt voor jullie meedenken tot zover.
Met vriendelijke groet, Wilfred Dijksman
[size=xsmall]Toevoeging op 31/01/2013 15:18:28:[/size]
Mijn excuses. Ik probeer een bericht te bewerken maar dat gaat even niet helemaal lekker. Mss dat een mod het voor elkaar krijg mijn berichten in te perken tot het laatst geposte bericht?
[size=xsmall]Toevoeging op 31/01/2013 15:21:26:[/size]
@Kirs Peeters, thnsx voor je snelle reactie. Een soortgelijke mogelijkheid zoals jij deze aandraagt is eerder al aangedragen. Probleem is dan dat de curl_session in de parent class een andere is dan in de child class. Dit moeten dezelfde zijn omdat de child class anders geen data kan ophalen (in de parent class wordt ingelogd, die sessie heeft child class nodig).
Mocht je nog vragen/opmerkingen/ideeën hebben, dan hoor ik het graag.
Dan vrees ik dat ik akkoord moet gaan dat met de eerste reactie van Erwin.
Het lijkt me niet wenselijk dat een extend members van zijn parent aanmaakt.
m.a.w. misschien is het beter dat je iets anders gebruikt dan een extend.
Tim Slootweg op 31/01/2013 14:55:43
Moet het dan perse een extension zijn?
Wilfred Dijksman op 31/01/2013 15:10:08
Ja, het is een systeem wat meerdere modules/apps heeft die wel dezelfde basis functies nodig hebben. Die basis functies zitten in de parent class.
Dit lijkt me geen goed OOP argument.
Dit is niet de reden waarom men een extend maakt.
Niets houdt je tegen om methodes uit een andere class aan te spreken.
- Je kan die functies statisch maken.
- Je kan een member van de hoofd-class meegeven aan de "child"; dan heb je ook diens methodes ook ter beschikking.
Over je mogelijke oplossing:
Probleem wordt dan dat er meerdere cUrl sessies komen omdat $this->ch dan twee keer wordt ingesteld op curl_init(); Voor de werking van het systeem is één dezelfde sessie in cUrl vereist (cUrl logt in de parent class in op een systeem en haalt in de child class data op uit datzelfde systeem. Dit moet in dezelfde cUrl sessie gebeuren omdat anders de login die cUrl heeft gedaan in de parent class verlopen is.).
Maar dat is dus juist niet waar in de code die ik je gaf. Alleen de allereerste keer dat getCh() wordt aangeroepen (hetzij door de parent, hetzij door de child) wordt $this->ch geinitialiseerd met curl_init(), daarna wordt elke keer de al geinitialiseerde sessie gebruikt. Dat was nu juist de grap van het voorbeeld dat ik je gaf.
@Erwin H: Ik begrijp je idee. Ik heb het geprobeerd. Maar in de praktijk wordt $this->ch twee keer geïnitialiseerd. Een class die extend neemt de properties en methoden mee maar niet de waarde van die properties die eerder zijn ingesteld (zo lijkt het in ieder geval).
Wilfred, heb je één cURL-verbinding nodig die wordt gedeeld door meerdere apps? En moet die verbinding een bepaalde tijd geopend blijven of gebruik je per verzoek een openen/sluiten-mechanisme? Is het resultaat van het cURL-verzoek misschien lokaal te cachen gedurende enkele seconden/minuten/uren of moet elk verzoek nieuwe externe data ophalen?
Als je maar één externe cURL-verbinding gebruikt die moet worden gedeeld door alle apps en sessies, is dat in wezen een singleton omdat je maar één instantie van het object gebruikt. Ondersteunt de externe server die de cURL-respons afhandelt bijvoorbeeld maximaal twee gelijktijdige verbindingen, dan kun je daarop een variant maken.
Een class die extend neemt de properties en methoden mee maar niet de waarde van die properties die eerder zijn ingesteld (zo lijkt het in ieder geval).
Dat is klinklare onzin. Een class die een andere class extend neemt de properties over inclusief alle waardes. Wat heb je anders aan private en protected properties?
Voorbeeld:
<?php
class Parent2{
private $test;
protected function getTest(){
if ( $this->test == null ){
echo 'init<br>';
$this->test = 'een waarde<br>';
}
return $this->test;
}
public function __construct(){
echo $this->getTest();
}
}
class Child2 extends Parent2{
public function geefTest(){
echo $this->getTest();
}
}
$obj = new Child2();
$obj->geefTest();
?>
Dit geeft als uitkomst:
init
een waarde
een waarde
Niet twee keer init dus, het private property wordt maar 1 keer geinitialiseerd.
Maar....
Wilfred Dijksman op 31/01/2013 22:00:47
@Erwin H: Ik begrijp je idee. Ik heb het geprobeerd. Maar in de praktijk wordt $this->ch twee keer geïnitialiseerd.
Dit is niet omdat je een class extend, maar omdat je twee instanties aanmaakt. In de constructor creeer je nog een instantie (via new $_GET['app'];) Daar ga je mis, want inderdaad, dan krijg je twee verschillende instanties met ieder hun eigen properties en eigen waardes. Daarmee kom je dus weer terug bij het feit dat je opzet gewoon, uhm, vreemd is.
Wat je moet doen, als je echt maar 1 instantie van curl wilt hebben, is dat deel uit je class halen en in een aparte class plaatsen. Je doet dit nu wel op een nogal vreemde manier, door de parent apart aan te maken (waardoor je dus een child krijgt die parent extend EN een parent instantie in een property heeft), maar zo krijg je hele vreemde connecties.
@Tim Slootweg: Mijn excuses, ik had je reactie over het hoofd gezien. Probleem is dat de parrent class twee keer wordt geïnitialiseerd. Dit probleem blijf je houden, ook met setters en getters lijkt me toch (dubbele curl session is dan idd wel opgelost, maar code blijft dan nog steeds weired)?
@Ward van der Put: De session die in curl start moet in de child dezelfde session zijn. De parent class logt in op een website (submit user/pass) en de child class haalt vervolgens data op van een andere pagina op dezelfde website (die alleen zichtbaar is als je bent ingelogd (dus session die geopend is in de parent class is nodig)). Wanneer de request van de remote is afgehandeld is de sessie niet meer nodig en hoeft deze dus ook niet aan de remote kant gecached te worden.
@Erwin: Haha, het kwam mijn idd ook over als klare onzin. En zoals ik eerder al heb gezegd: mijn code(opbouw) zal hoogst waarschijnlijk een groot aantal verbeter punten hebben. Ik ben mijzelf dan ook bewust van het feit dat mijn huidige oplossing een slechte work-around is. Overigens heb ik je verhaal vandaag meerdere keren moeten doorgelezen om het goed te begrijpen.
Volgens mij begrijp je mij alleen verkeerd (of ik jou :s): Via new $_GET['app']; wordt de child class geïnitialiseerd (en niet de parrent class (voor een tweede keer)). Van de parent class is dus maar 1 instantie. In de parent class komt daar een instantie van de child class bij. Van beide classes is dus één instantie (zou ik zeggen).
Maybe I'm wrong… ;) Iig nogmaals dank voor jullie hulp en tijd voor zover!
Wilfred Dijksman
[size=xsmall]Toevoeging op 02/02/2013 22:57:16:[/size]
[size=xsmall]Toevoeging op 31/01/2013 15:12:44:[/size]
Ja, het is een systeem wat meerdere modules/apps heeft die wel dezelfde basis functies nodig hebben. Die basis functies zitten in de parent class.
[size=xsmall]Toevoeging op 31/01/2013 15:10:14:[/size]
Ik heb ondertussen een oplossing voor mijn probleem:
Ik laad een variabele met daarin het parent class object in de child class zodat via die variabele alles toegankelijk is vanuit de child class. Zie ook het voorbeeld hieronder:
parent.class.php
<?php
class Parent{
private $app;
function __construct(){
loadChild($var);
}
function loadChild($nameClass){
include('lib/'.$nameClass.'.class.php');
$this->app = new $nameClass($this);
}
function getSomething($what){
return($what);
}
}
?>
child.class.php
<?php
class Child{
private $parent_object;
function __construct($parent_object){
$this->parent_object = $parent_object;
// execute methode from Parent class
$this->parent_object->getSomeThing();
}
}
?>
Opmerking: Nadeel van deze methode is natuurlijk wel dat de visability van properties en methodes omzeilt wordt.
Mochten jullie nog opmerkingen / andere suggesties hebben dan hoor ik dat graag. Nogmaals dankt voor jullie meedenken tot zover.