[PHP] Classes in andere classes gebruiken

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • DannyBevers
  • Registratie: November 2009
  • Laatst online: 07:03
Hallo devs,

Sinds een lange tijd ben ik bezig mijn eigen source te gaan verbeteren en dus flink aan het testen. Nu wil ik verschillende classes bij elkaar zetten in 1 configuratie php bestand dus alle classes daarin include.

Vervolgens roep ik ze allemaal in het bestand op.

PHP:
1
2
3
4
5
6
$signin         = new Signin();
$signup         = new Signup();
$signout        = new Signout();
$lostpassword   = new Lost_password();
$bank           = new Bank();
$forum          = new Forum();


Maar nu doe ik alles via een global in de functies oproepen dat is ten boze lees ik overal ene kant snap ik het je moet constant weer die class omtoveren in een global wat onnodig word maar het is mij zo aangeleerd helaas.

Nu zoek ik al een tijdje de oplossing om dit niet meer te gebruiken en had ik het op deze manier gebouwd.

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
class Configuration 
{
    private $db;
    private $signin;

    public function __construct($db, $signin)
    {
        $this->db = $db;
        $this->signin = $signin;
    }

    public function getMessage($messageId)
    {
        return $this->db->field("SELECT `message_text` FROM 
                            `page_message` 
                           WHERE 
                           `message_id` = '" . $messageId . "' AND 
                           `message_language` = '" . (isset($_SESSION['language']) ? $_SESSION['language'] : 'nl') . "'");
    }
}

$db             = new Database;
$signin         = new Signin($db);
$config         = new Configuration($db, $signin);


Maar dit ging natuurlijk niet werken als ik de configuration class wil inladen in de Signin class want die word pas later aangemaakt.

Mijn vraag is hoe ga ik dit oplossen dat in de $config en $db in de new Signin() kan gebruiken aldus in het bestand signin.class.php?

Hoop dat iemand mij de informatie kan geven waar ik nog veel van kan leren en tenminste van de globals af ben :F

Alvast bedankt :>

Acties:
  • 0 Henk 'm!

  • X_lawl_X
  • Registratie: September 2009
  • Laatst online: 11-09 16:13
Je eigen oplossing is al beter, hoewel je beter dit kan doen met type hinting

PHP:
1
2
public function __construct(Database $db)
{}

Dit zorgt ervoor dat het 1e argument persé een instance moet zijn van de Database class.

Wat betreft jou probleem, ik denk dat je het helemaal verkeerd hebt aangepakt. (Wat moet een configuratie class met een signin class?) Misschien moet je eens naar het MCV model kijken.

[ Voor 24% gewijzigd door X_lawl_X op 25-01-2011 20:40 ]


Acties:
  • 0 Henk 'm!

  • ReenL
  • Registratie: Augustus 2010
  • Laatst online: 14-09-2022
Ik begrijp de vraag niet goed, wat is "Configuration"?

Om de files bij de classes te zoeken, gebruik je de autoload functie, op die manier include je niets wat je niet nodig hebt, en kun je ook niet vergeten iets te includen, elke class zijn eigen file.

Acties:
  • 0 Henk 'm!

  • DannyBevers
  • Registratie: November 2009
  • Laatst online: 07:03
X_lawl_X schreef op dinsdag 25 januari 2011 @ 20:31:
Je eigen oplossing is al beter, hoewel je beter dit kan doen met type hinting

PHP:
1
2
public function __construct(Database $db)
{}

Dit zorgt ervoor dat het 1e argument persé een instance moet zijn van de Database class.

Wat betreft jou probleem, ik denk dat je het helemaal verkeerd hebt aangepakt. (Wat moet een configuratie class met een signin class?) Misschien moet je eens naar het MCV model kijken.
Aha bedankt al voor de tip voor MCV model zal ik is gaan kijken. Ja ik heb teveel in elkaar proberen te bouwen wat erg onnodig was. Maar ik ga me morgen verdiepen in de MCV models.

Alvast bedankt voor de type hinting tip. Ik ga er wat mee doen :)

--

ReenL

Dus jij raad gewoon aan alle includes weg te halen en een __autoload in de config class zetten zodat alles al word ingeladen neem ik aan?

Mijn vraag is hoe ik uit een x aantal classes bestanden de functies kan gebruiken van elkaar.

[ Voor 12% gewijzigd door DannyBevers op 25-01-2011 20:49 ]


Acties:
  • 0 Henk 'm!

  • Webgnome
  • Registratie: Maart 2001
  • Laatst online: 19:32
DannyBevers schreef op dinsdag 25 januari 2011 @ 20:47:
[...]


Aha bedankt al voor de tip voor MCV model zal ik is gaan kijken. Ja ik heb teveel in elkaar proberen te bouwen wat erg onnodig was. Maar ik ga me morgen verdiepen in de MCV models.

Alvast bedankt voor de type hinting tip. Ik ga er wat mee doen :)

--

ReenL

Dus jij raad gewoon aan alle includes weg te halen en een __autoload in de config class zetten zodat alles al word ingeladen neem ik aan?

Mijn vraag is hoe ik uit een x aantal classes bestanden de functies kan gebruiken van elkaar.
Het gaat niet zo zeer om het mvc model (waarom wordt dat in php toch altijd tot de heilige graal gerekend.. ) maar meer over de verantwoordelijkheden van je classes. Bedenkt goed waar je welke class voor wilt gaan gebruiken. Welk deel van je proces(-sen) representeerd een class. Als je dat duidelijk hebt zie je dat een signin object juist een config nodig heeft en niet andersom (heel simpel gesteld )

Strava | AP | IP | AW


Acties:
  • 0 Henk 'm!

  • YopY
  • Registratie: September 2003
  • Laatst online: 13-07 01:14
Ten eerste, je zit op het goede spoor, props voor dat :).

Wat je probleem lijkt te zijn is dat je een circulaire afhankelijkheid hebt - je signin is afhankelijk van je config en vice-versa (als ik je opmerking goed lees, je code zegt van niet). Hoe je dat op zou moeten lossen - geen idee, dan zou ik moeten weten wat die classes doen en hoe ze precies van elkaar afhankelijk zijn.

Je zou je code ook logischer op kunnen delen. Je hebt een logisch object 'configuration', maar haalt daar 'messages' mee op. Ik zie ook niet waarom een Configuratie een Signin zou moeten hebben, en ook niet wat voor logisch iets een class Signin behoort te zijn.

Overigens kun je (vzviw) in PHP geen classes in andere classes gebruiken. Wel instanties in andere instanties, en ook kun je bestanden includen zodat je instanties aan kunt maken. Even muggenziften, excuus :+.
Mijn vraag is hoe ik uit een x aantal classes bestanden de functies kan gebruiken van elkaar.
Ah. Precies zoals je het deed.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Henk {
    public function doeIets($param) { 
       // ja
    }
}
class Pietje {
    private $henk;

    public function _construct(Henk $henk) {
        $this->henk = $henk;
    }

    public function doeIetsMetHenk($param) {
        $this->henk->doeIets($param);
    }
}

$henk = new Henk();
$pietje = new Pietje($henk);
$pietje->doeIetsMetHenk('klaas!');


en voor de rest zou ik het zo niet weten. Hier en daar een include / require of hun _once varianten of autoload inrichten, en hoed je voor circular dependencies.

Acties:
  • 0 Henk 'm!

  • ProperChaos
  • Registratie: December 2007
  • Niet online
-

[ Voor 100% gewijzigd door ProperChaos op 04-01-2021 16:14 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Waarom zou je van een database class een singleton maken? Ik heb genoeg situaties gezien waarbij verbinding moest worden gemaakt met verschillende databases. Leer het gewoon even iets netter te doen.

Acties:
  • 0 Henk 'm!

  • ProperChaos
  • Registratie: December 2007
  • Niet online
-

[ Voor 100% gewijzigd door ProperChaos op 04-01-2021 16:14 ]


Acties:
  • 0 Henk 'm!

  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06 13:31

drm

f0pc0dert

ProperChaos:
Dat is dus wat ik probeer te bereiken met mijn vraag. ;)
En je hebt gelijk wat betreft de database class, slecht voorbeeld. Zelfde vraag voor een andere singleton class.
Het vervelende van singletons is dat je daarmee een afhankelijkheid hebt naar een (implementatie van) een bepaalde class of interface die niet van buitenaf duidelijk, én niet beïnvloedbaar is. Dat eerste maakte je code ondoorzichtig, het tweede maakt het testen van je code heel erg lastig, omdat je met tests die onderdelen vaak moet kunnen mocken of stubben. Als je dat niks zegt moet je eens wat gaan lezen over en spelen met TDD, heel erg interessante materie en een goede confronterende methode om heldere en gestructureerde code te schrijven. Over het algemeen betekent goed testbare code ook goed uitbreidbare code.

Verder is het misschien wel eens leuk een beetje in te lezen over Dependency Injection en DI containers, iets wat in PHP land de laatste tijd nogal een hippe term is.

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


Acties:
  • 0 Henk 'm!

  • DannyBevers
  • Registratie: November 2009
  • Laatst online: 07:03
Na de reacties gelezen te hebben kom ik eruit dat mijn basis structuur teveel afwijkt van de logica. Bedankt allen voor de tips hier heb ik echt wat aan.

Ga mijn opzet nu eens aanpassen dat er logica inzit, want zoals jullie al zeggen is de logica gewoon niet goed wat ik nu ook zelf zie.

Heel erg bedankt alvast!

Acties:
  • 0 Henk 'm!

  • YopY
  • Registratie: September 2003
  • Laatst online: 13-07 01:14
ProperChaos schreef op dinsdag 25 januari 2011 @ 22:57:
Even wat gerelateerds: als de DB class een singleton is, is het dan goed/mooi/good practise om het volgende te doen?

PHP:
1
2
3
4
5
6
class Piet {
    public function Foo() {
        $db = DB::getInstance();
        // doe iets met $db
    }
}

Of is $db meegeven als param voor Foo() netter?
$db is een service, Piet is afhankelijk van die service voor zijn gebruik. Ergo, bij initialisatie van class Piet zou je de $db service gelijk me moeten geven. De Piet class zou niet eens geïnitialiseerd moeten kunnen worden als hij geen $db heeft.

PHP:
1
2
3
4
5
6
7
8
9
class Piet {
   private $db;
   public function __construct(Db $db) {
       if ($db == null) {
           throw new PietInitializationException("db cannot be null");
       }
       $this->db = $db;
   }
}

[ Voor 15% gewijzigd door YopY op 26-01-2011 09:29 ]


Acties:
  • 0 Henk 'm!

  • Webgnome
  • Registratie: Maart 2001
  • Laatst online: 19:32
YopY schreef op woensdag 26 januari 2011 @ 09:26:
[...]


$db is een service, Piet is afhankelijk van die service voor zijn gebruik. Ergo, bij initialisatie van class Piet zou je de $db service gelijk me moeten geven. De Piet class zou niet eens geïnitialiseerd moeten kunnen worden als hij geen $db heeft.

PHP:
1
2
3
4
5
6
7
8
9
class Piet {
   private $db;
   public function __construct(Db $db) {
       if ($db == null) {
           throw new PietInitializationException("db cannot be null");
       }
       $this->db = $db;
   }
}
Dat hangt er helemaal maar vanaf. Het is leuk dat de pietclass een connectie heeft met een database maar wat representeerd piet? als dit de persoon PIET is dan is het toch veel beter om een PIETDao te schrijven? Hier knikker je pietjes in , haal je pietjes uit.. Het object Piet zou het niet uit mogen maken waar hij vandaan komt of waar hij/zij de data vandaan haalt.

Strava | AP | IP | AW


Acties:
  • 0 Henk 'm!

Verwijderd

even my 2 cents,

Het gebruik van een autoload structuur is, zoals velen al aangeven, erg gewenst. Hier zijn veel verschillende methodes voor, van het bijhouden van een aantal include paths tot het maken van een directe link tussen de classname en het pad waar de class te vinden is (zoals Zend het doet).

Wat ook al aangegeven is is dat een Database singleton je in vele gevallen beperkt, terwijl het los gebruik van vele database instances ook niet altijd is wat je wil.
Een veelgebruikte oplossing hiervoor is door gebruik te maken van Connection Pooling, dus een class (meestal een static) die je instances van je Database class bijhoudt die je dan bijvoorbeeld dmv een naam op kunt vragen, het mooie van deze oplossing is dat deze later toe te voegen indien je meerdere databases nodig hebt.
Het gaat niet zo zeer om het mvc model (waarom wordt dat in php toch altijd tot de heilige graal gerekend.. )
:

Dit is niet alleen in PHP, in bijna alle programmeertalen zijn er n-Tier oplossingen zoals MVC of PAC en het is niet zo zeer een heilige graal als gewoon common sense of best practice.

MVC is in wezen niets meer dan een methode om Seperation Of Concern toe te passen, met andere woorden het scheiden van verantwoordelijkheden.

bijvoorbeeld hoeft je HTML weergave van je lijst met favoriete cd's niet te weten waar de data vandaan komt en op de plek waar je de data ophaalt hoef je eigenlijk niet te weten dat de data in HTML weergegeven gaat worden. De n-Tier methodiek zorgt daarnaast voor code die goede te herbruiken is.

Acties:
  • 0 Henk 'm!

  • Ssander
  • Registratie: December 2009
  • Laatst online: 12-06-2023
Verwijderd schreef op dinsdag 25 januari 2011 @ 22:59:
Waarom zou je van een database class een singleton maken? Ik heb genoeg situaties gezien waarbij verbinding moest worden gemaakt met verschillende databases. Leer het gewoon even iets netter te doen.
Ik snap dit argument nooit helemaal. Dit is toch vrij simpel op te lossen?

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
<?php
class Piet {
    public function Foo() {
        $dbslave1 = DB::getInstance(DATABASE_CONNECTION_SLAVE1);
        // doe iets met $dbslave1

        // andere connectie nodig
        $dbmaster = DB::getInstance(DATABASE_CONNECTION_MASTER);
        // doe iets met $dbmaster
    }
}
?>

Ik weet eerlijk gezegd niet of dit ook een bekend patroon is. Misschien iets als Multi-Singleton, hoe paradoxaal dat ook mag klinken. Maar is dit de nettere manier waarnaar je verwijst?

Acties:
  • 0 Henk 'm!

  • Webgnome
  • Registratie: Maart 2001
  • Laatst online: 19:32
Verwijderd schreef op woensdag 26 januari 2011 @ 09:53:
even my 2 cents,

[...]
:

Dit is niet alleen in PHP, in bijna alle programmeertalen zijn er n-Tier oplossingen zoals MVC of PAC en het is niet zo zeer een heilige graal als gewoon common sense of best practice.

MVC is in wezen niets meer dan een methode om Seperation Of Concern toe te passen, met andere woorden het scheiden van verantwoordelijkheden.

bijvoorbeeld hoeft je HTML weergave van je lijst met favoriete cd's niet te weten waar de data vandaan komt en op de plek waar je de data ophaalt hoef je eigenlijk niet te weten dat de data in HTML weergegeven gaat worden. De n-Tier methodiek zorgt daarnaast voor code die goede te herbruiken is.
Begrijp mij niet verkeerd ik weet echt wel wat het MVC pattern tot doel heeft echter is dat in deze context niet eens zo heel erg van belang. TS wil weten hoe het beste om te gaan met dependencies van classes etc. Dan is het eerst zaak om goed aan te leren hoe dat je een class structure op zet ( entiteiten erkennen, verantwoordelijkheden bepalen etc.. ) . Als die slecht is dan kun je er van allerlei patterns tegenaan gooien maar je basis is en blijft slecht.

Strava | AP | IP | AW


Acties:
  • 0 Henk 'm!

Verwijderd

@Webgnome :
Dat was in dit geval ook inderdaad in deze context niet echt belangrijk. Al is het scheiden van verantwoordelijkheden en het denken hierover wel enigszins verbonden met hoe dependencies tussen objecten liggen.

Ik geloof ook niet dat er 1 concreet antwoord op de vraag is, ieder type project vereist, tot op bepaalde hoogte, een andere opzet.

Wel raad ik aan om bijvoorbeeld het inladen van data zoals in de Configuration class niet direct te doen maar via een abstractielaag zoals een model/DAO , waardoor je de dependency met een database al kwijt bent en het hierdoor makkelijker zou zijn om andere datasources aan te spreken.

je zou dan iets krijgen in de geest van
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/** de database wordt als default db adapter in de modelfactory gezet zodat bij iedere ModelFactory::create automatisch de goede Db instance meegegeven wordt **/
$maindb = DbManager::getConnection('main');
ModelFactory::setDefaultDb($maindb);



/** init van de config **/
$config = new Configuration( ModelFactory::create('ConfigModel') );

class Configuration
{
  protected $_model;
  class __construct(Model $model)
  {
    $this->_model = $model;
  }

  public function getMessage($id)
  {
    $message = $this->_model->getMessageById($iId);
    return $message;
  }
}

Acties:
  • 0 Henk 'm!

Verwijderd

Ik heb hier een Core Class voor gemaakt waarmee het mogelijk is om vanuit elke class een andere class te laden.

Voorbeeld:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// include the class 
require_once('core.class.php'); 

// create object 
$core = new Core(); 


// EXAMPLE CODES 

// add database object 
$core->Database; 

// use database object 
$core->Database->query("SELECT ..."); 

// add variable and print later 
$core->test = 'test'; 
print $core->test;


Broncode en voorbeeld is te vinden op http://www.phpclasses.org...ad-framework-objects.html

Acties:
  • 0 Henk 'm!

  • YopY
  • Registratie: September 2003
  • Laatst online: 13-07 01:14
Webgnome schreef op woensdag 26 januari 2011 @ 09:40:
[...]


Dat hangt er helemaal maar vanaf. Het is leuk dat de pietclass een connectie heeft met een database maar wat representeerd piet? als dit de persoon PIET is dan is het toch veel beter om een PIETDao te schrijven? Hier knikker je pietjes in , haal je pietjes uit.. Het object Piet zou het niet uit mogen maken waar hij vandaan komt of waar hij/zij de data vandaan haalt.
Natuurlijk, was ook een triviaal voorbeeld en een halve copypasta van een voorgaande post. Je hebt natuurlijk helemaal gelijk.
Verwijderd schreef op woensdag 26 januari 2011 @ 16:45:
Ik heb hier een Core Class voor gemaakt waarmee het mogelijk is om vanuit elke class een andere class te laden.

[...]

Broncode en voorbeeld is te vinden op http://www.phpclasses.org...ad-framework-objects.html
Klinkt als het God Object pattern (zie ook het iets humoristischer artikel op C2 wiki). Kan natuurlijk ook geïnterpreteerd worden als een singleton-dat-singletons bevat of, in officiëler termen, een Service Locator. Edit: Die laatsten, het zou een god object (volgens wikipedia) zijn als er meer daadwerkelijke applicatielogica in stond. Nu valt natuurlijk het initialiseren van een databaseverbinding ook onder applicatielogica, dus als het ook maar iets anders doet zou je het al als een antipattern kunnen zien.

[ Voor 9% gewijzigd door YopY op 26-01-2011 17:03 ]


Acties:
  • 0 Henk 'm!

  • ReenL
  • Registratie: Augustus 2010
  • Laatst online: 14-09-2022
@Ssander:
Lost nog steeds niet het probleem op dat je afhankelijkheden onzichtbaar worden. In je multi-ton moet je vervolgens altijd een "key" meegeven. Hoe weet je tijdens het initialiseren welke "keys" er verwacht worden? Hoe weten je classes welke key ze moeten gebruiken?

@Terminal13:
Dat noemen ze een registry pattern. En is wat mij betreft bad practice. Wat als je $core->Database op de een of andere manier nog null/leeg is en jij gaat er op zitten querien? Is het de verantwoordelijkheid voor class die hier dan gebruikt van maakt om alsnog een instance te maken? Ga je een NullPointer gooien, terwijl je API geen database "verplicht"? Plus, code completion gaat in de meeste editors over zijn nek. Daarnaast, hetzelfde als met singleton, hoe kan je aan de API zien dat je classe afhankelijk is van een andere classe?

Acties:
  • 0 Henk 'm!

  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06 13:31

drm

f0pc0dert

ReenL:
@Ssander:
Lost nog steeds niet het probleem op dat je afhankelijkheden onzichtbaar worden. In je multi-ton moet je vervolgens altijd een "key" meegeven. Hoe weet je tijdens het initialiseren welke "keys" er verwacht worden? Hoe weten je classes welke key ze moeten gebruiken?
Er zou maar één onderdeel in je applicatie verantwoordelijk moeten zijn voor de keuze welke verbinding gebruikt moet worden. Dat is precies separation of concern. Het feit dat er ueberhaupt een verbinding ís, laat staan meerdere, is voor de rest van de applicatie helemaal niet van belang. Die zeggen gewoon tegen de de DBAL: "Hé, sla dit eens voor me op", of "Hé, geef mij eens dit en dit terug wat ik eerder al eens aan je gevraagd heb voor me op te slaan". Hoe die DBAL dat verder doet "moet 'ie lekker zelf weten".
ReenL:
@Terminal13:
Dat noemen ze een registry pattern. En is wat mij betreft bad practice. Wat als je $core->Database op de een of andere manier nog null/leeg is en jij gaat er op zitten querien? Is het de verantwoordelijkheid voor class die hier dan gebruikt van maakt om alsnog een instance te maken? Ga je een NullPointer gooien, terwijl je API geen database "verplicht"? Plus, code completion gaat in de meeste editors over zijn nek. Daarnaast, hetzelfde als met singleton, hoe kan je aan de API zien dat je classe afhankelijk is van een andere classe?
Dit raakt eigenlijk twee onderdelen: enerzijds het instantieren en initialiseren van services (waar doe je dat, en wie is daar verantwoordelijk voor) en aan de andere kant het zorgen dat je classes die afhankelijk zijn van die services weten dat de services beschikbaar zijn.

Het eerste wordt wel bootstrapping genoemd, vergelijkbaar met OS bootstrapping, waarbij ook services afhankelijk zijn van anderen, maar waar je uiteindelijk vooral geïnteresseerd bent in het draaien van het OS, niet zo zeer in het draaien van de services afzonderlijk. Het tweede wordt ook wel "dependency injection" genoemd, maar dat is eigenlijk alleen maar een mooie term voor het initialiseren van objecten met die services waar de objecten van afhankelijk zijn.

Daarom noemde ik eerder al het idee van een DI container. Lees deze post en de daarop volgende artikeltjes over het onderwerp.. Ik ben geen fan van de beste man, maar dit is echt leuk materiaal omdat het heel erg praktisch vanuit PHP-hoek gedacht is en tegelijkertijd dit soort belangrijke design-issues aansnijdt.

Dat wil overigens niet zeggen dat ik vind dat je overal maar zo'n DI container tegenaan moet gooien, het gaat meer om de paradigma's en design-voordelen die het oplevert.

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz

Pagina: 1