[PHP][OOP]Object doorgeven aan ander object

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • XxKr0n3xX
  • Registratie: Januari 2004
  • Niet online
Hoi,

Ik heb gezocht op het doorgeven van objecten aan andere objecten maar de zoekresultaten hebben me nog niet verder geholpen.

Ik heb in mijn webapplicatie 4 bestanden:
  • gebruiker.class.php
    Hierin worden wat gebruiker specifieke functies uitgevoerd. Login / Logout etc.
  • sessie.class.php
    Hierin worden wat sessie specifieke functies uitgevoerd.
  • db.class.php
    Hierin staan query functies en wordt de database connectie opgezet.
  • config.php
    Hierin worden de database en gebruikers klasse geinitialiseerd.
  • index.php
    De hoofdpagina van de webapp.
In de pagina config.php wordt het database object geinitialiseerd.
PHP:
1
$db=new Database();


Ik wil echter gebruik maken van het $db object in de gebruikers klasse en de sessie klasse. Nu intialiseer ik het object opnieuw binnen de gebruikers klasse zijn constructor. Dit voert een nieuwe connectie uit naar de db terwijl ik eigenlijk gewoon bovenstaande object wil blijven gebruiken. Hetzelfde geld voor de sessie klasse.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Gebruiker
 {
   public $gebruiker_id;

   public function __construct($gebruiker_id)
     {
      $this->gebruiker_id=$gebruiker_id;
      
      $db=new Database();
      
       $this->db=$db;
      
        }
}


Bovenstaande wil ik dus niet voor iedere nieuwe klasse doen. Mijn idee was dan ook om een soort hoofdklasse te maken en daar het aangemaakte $db object aan mee te geven.

Wellicht doe ik iets verkeerd maar zodra ik dit dus doe en die hoofdklasse extend naar bijvoorbeeld de gebruikers klasse kan ik geen functies uitvoeren met het $db object.

Kan iemand me aan duwtje in de juiste richting geven?

Acties:
  • 0 Henk 'm!

  • AtleX
  • Registratie: Maart 2003
  • Niet online

AtleX

Tyrannosaurus Lex 🦖

Een singleton zou hier prima op z'n plaats zijn, je wilt immers maar 1 connectie naar je database hebben. :)

Sole survivor of the Chicxulub asteroid impact.


Acties:
  • 0 Henk 'm!

  • ikke007
  • Registratie: Juni 2001
  • Laatst online: 18-09 14:10
Je kunt hiervoor zoals AtleX zegt een Singleton gebruiken, alhoewel dit wel weer andere problemen introduceert (testbaarheid en modulaire opbouw wordt minder)

Je kunt ook gewoon je databaseconnection aan de constructor meegeven

PHP:
1
2
3
4
5
class gebruiker{
  public function __construct($aGebruikerId,$aDatabaseConnection){
    $this->db = $aDatabaseConnection;
  }
}

[ Voor 3% gewijzigd door ikke007 op 30-07-2008 11:07 . Reden: <?php versus [code] tags ]

Lets remove all security labels and let the problem of stupidity solve itself


Acties:
  • 0 Henk 'm!

  • XxKr0n3xX
  • Registratie: Januari 2004
  • Niet online
Singleton is een nieuwe term voor mij. Ik zal eens even googlen.

Maar als ik me $db object aan mijn constructor wil meegeven zou dus iedere keer als het gebruikersobject initialiseer daar ook de $db aan mee moeten geven. En dit dus voor ieder ander object moeten doen wat initialiseer als ik daar db connectivity in nodig heb?

dus

PHP:
1
2
$db=new Database();
$gebruikerObj=new Gebruiker($gebruiker_id,$db);


?

Acties:
  • 0 Henk 'm!

  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

AtleX schreef op woensdag 30 juli 2008 @ 11:04:
Een singleton zou hier prima op z'n plaats zijn, je wilt immers maar 1 connectie naar je database hebben. :)
Nee, je wilt alleen een connectie naar je database hebben zodra je deze nodig hebt. Dus geen globale connectie per page. Dat zou namelijk de efficientie van je database beperken . PHP heeft een goede connectionpool waarmee de overhead tot een minimum beperkt wordt. Als de pool nog een connectie beschikbaar heeft, is er zelfs vrijwel geen overhead.

Een singleton zorgt ervoor dat je slechts 1 referentie (instance) hebt naar je database class. Afhankelijk van hoe de database class is geschreven worden voor en na het uitvoeren van de query de verbinding naar de database geopend of gesloten.

If it isn't broken, fix it until it is..


Acties:
  • 0 Henk 'm!

  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

XxKr0n3xX schreef op woensdag 30 juli 2008 @ 11:24:
Singleton is een nieuwe term voor mij. Ik zal eens even googlen.

Maar als ik me $db object aan mijn constructor wil meegeven zou dus iedere keer als het gebruikersobject initialiseer daar ook de $db aan mee moeten geven. En dit dus voor ieder ander object moeten doen wat initialiseer als ik daar db connectivity in nodig heb?

dus

PHP:
1
2
$db=new Database();
$gebruikerObj=new Gebruiker($gebruiker_id,$db);
Ik zou zelfs de database connectie nog nieteens meegeven aan de Gebruiker class. De constructor kan dan namelijk zelf bepalen of hij een verbinding opzet naar de database of bijvoorbeeld een instance van Gebruiker in een sessie opslaat (cache) zodat niet bij iedere page request een verbinding naar de database nodig is. Ook kun je later vrij eenvoudig een webservice gebruiken voor het ophalen van de gebruiker gegevens in plaats van een database.

Google ook maar eens op keywords zoals database abstractie (layer) en MVC (Model View Controller).

If it isn't broken, fix it until it is..


Acties:
  • 0 Henk 'm!

  • prototype
  • Registratie: Juni 2001
  • Niet online

prototype

Cheer Bear

XxKr0n3xX schreef op woensdag 30 juli 2008 @ 11:24:
Singleton is een nieuwe term voor mij. Ik zal eens even googlen.

Maar als ik me $db object aan mijn constructor wil meegeven zou dus iedere keer als het gebruikersobject initialiseer daar ook de $db aan mee moeten geven. En dit dus voor ieder ander object moeten doen wat initialiseer als ik daar db connectivity in nodig heb?

dus

PHP:
1
2
$db=new Database();
$gebruikerObj=new Gebruiker($gebruiker_id,$db);


?
Zou ik niet doen, worden je vingers moe van namelijk :P En andermans ogen worden er ook moe van als ze dat elke keer zo moeten zien. Singleton pattern zoals deze genoemd is in dit topic is een mogelijke oplossing indien je ook echt alles binnen je scripts over ten hoogste 1 connectie wil laten gaan (indien dat niet het geval is zoek je een connection pool pattern), maar als ik 't zo bekijk zoek jij volgens mij meer een object relational mapper (nog een term misschien om even naar te googlen). In het bijzonder zou ik even kijken naar het Active Record pattern.

P.S. Ook al heb ik toevallig nu enkele design patterns genoemd, dat impliceert nog niet dat design patterns de oplossing zijn die 't beste passen bij jou. Ik zou er vooral eerst even mee spelen zodat je precies door hebt wat de implicaties zijn van het toepassen van dergelijke patterns.

[ Voor 11% gewijzigd door prototype op 30-07-2008 15:20 ]


Acties:
  • 0 Henk 'm!

  • SchizoDuckie
  • Registratie: April 2001
  • Laatst online: 18-02 23:12

SchizoDuckie

Kwaak

Ik heb in m'n sig een aantal simpele examples staan die je heel wat werk kunnen besparen denk ik :)

Stop uploading passwords to Github!


Acties:
  • 0 Henk 'm!

Verwijderd

Natuurlijk wel polymorphen als het kan...

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
class User{
     
     protected $db = null;
 
     //afdwingen dat $db een Database class object is...
     public function __construct(Database $db){
           $this->db = $db;
     }
}

$database = new Database();
$user = new User($db);
?>


of je moet met een factory pattern aan de slag eventueel...

[ Voor 10% gewijzigd door Verwijderd op 30-07-2008 19:35 ]


Acties:
  • 0 Henk 'm!

  • XxKr0n3xX
  • Registratie: Januari 2004
  • Niet online
Bedankt voor alle tips.

Ik ben bekend met MVC. Heb al een paar keer gespeeld met codeigniter. Wat ik nu echter wil bouwen is meer spielerij en heb geen behoefte aan CI.

Ik ben al aan het rondkijken op de diverse links. Voor mijn pagina is 1 database connectie per gebruiker nodig omdat mensen hun eigen paginaatje krijgen binnen de webapp waar ze dingen kunnen uploaden aanpassen etc.

Voor mijn database maak ik vooral gebruik van sprocs (stored procedures) kunnen deze ook via bijv Pork uitgevoerd worden?

Daarnaast wordt veel data in memcache weggeschreven om database traffic tot een minimum te brengen. Ook views (template html) wordt gecached in memcache voordat de app het van schijf gaat vissen.

[ Voor 51% gewijzigd door XxKr0n3xX op 30-07-2008 20:07 ]


Acties:
  • 0 Henk 'm!

  • SchizoDuckie
  • Registratie: April 2001
  • Laatst online: 18-02 23:12

SchizoDuckie

Kwaak

XxKr0n3xX schreef op woensdag 30 juli 2008 @ 19:57:

Voor mijn database maak ik vooral gebruik van sprocs (stored procedures) kunnen deze ook via bijv Pork uitgevoerd worden?
Dat hangt er een beetje vanaf hoe je werkt met je stored procedures... Ik heb ze zelf nog nooit nooit nodig gehad, en pork gaat uit van simpele tabellen met een auto-increment id en wat velden. Alles wat er gegenereerd wordt is select,insert en join statements.

Je zou best er zo een execute statement functie in de database class kunnen hangen, maar ik vraag me dus een beetje af wat dat dan zou moeten doen ?
Mag ik vragen wat je allemaal voor stored procedures gebruikt dan voor wat (naar wat het nu lijkt) een soort van profiel pagina is?

Stop uploading passwords to Github!


Acties:
  • 0 Henk 'm!

  • XxKr0n3xX
  • Registratie: Januari 2004
  • Niet online
SchizoDuckie schreef op woensdag 30 juli 2008 @ 20:50:
[...]

Dat hangt er een beetje vanaf hoe je werkt met je stored procedures... Ik heb ze zelf nog nooit nooit nodig gehad, en pork gaat uit van simpele tabellen met een auto-increment id en wat velden. Alles wat er gegenereerd wordt is select,insert en join statements.

Je zou best er zo een execute statement functie in de database class kunnen hangen, maar ik vraag me dus een beetje af wat dat dan zou moeten doen ?
Mag ik vragen wat je allemaal voor stored procedures gebruikt dan voor wat (naar wat het nu lijkt) een soort van profiel pagina is?
Queries uit de code weg te halen dus de code schoner maken en de database laag scheiden van de code laag. Normaliter zou je dit in je model kunnen zetten dat ben ik me bewust maar ik vond het wel een mooie oplossing die de code mooi schoon en overzichtelijk houdt.

Acties:
  • 0 Henk 'm!

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-09 00:37

curry684

left part of the evil twins

Niemand_Anders schreef op woensdag 30 juli 2008 @ 11:27:
[...]

Nee, je wilt alleen een connectie naar je database hebben zodra je deze nodig hebt. Dus geen globale connectie per page. Dat zou namelijk de efficientie van je database beperken . PHP heeft een goede connectionpool waarmee de overhead tot een minimum beperkt wordt. Als de pool nog een connectie beschikbaar heeft, is er zelfs vrijwel geen overhead.

Een singleton zorgt ervoor dat je slechts 1 referentie (instance) hebt naar je database class. Afhankelijk van hoe de database class is geschreven worden voor en na het uitvoeren van de query de verbinding naar de database geopend of gesloten.
Ik heb echt geen idee wat je nu probeert te zeggen. Daar PHP in webomgevingen per definitie singlethreaded is is er geen enkel probleem mee, sterker nog het zal in veel gevallen de meest gewenste oplossing zijn, om de databaseverbinding als een connect-on-demand singleton uit te voeren. PHP's connection pool heeft daar geen bal mee van doen, die zorgt ervoor dat 5 simultane requests 5 connecties weggeabstraheerd in de pool leggen die vervolgens waar nodig door volgende requests uit de pool gehaald worden.

Professionele website nodig?


Acties:
  • 0 Henk 'm!

  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

curry684 schreef op woensdag 30 juli 2008 @ 23:21:
[...]

Ik heb echt geen idee wat je nu probeert te zeggen. Daar PHP in webomgevingen per definitie singlethreaded is is er geen enkel probleem mee, sterker nog het zal in veel gevallen de meest gewenste oplossing zijn, om de databaseverbinding als een connect-on-demand singleton uit te voeren. PHP's connection pool heeft daar geen bal mee van doen, die zorgt ervoor dat 5 simultane requests 5 connecties weggeabstraheerd in de pool leggen die vervolgens waar nodig door volgende requests uit de pool gehaald worden.
Als PHP als apache (IIS) module draait zijn PHP (vanaf versie 4) wel degelijk ingebouwde connectionpool en andere nuttige features aanwezig. Als PHP draait in CGI-mode dan maakt het niet inderdaad niet zoveel uit. Behalve dan natuurlijk als je meer bezoekers krijgt dan database connecties mogelijk zijn. Door alleen verbinding met de database te maken als dat nodig (dus bij het uitvoeren van een query) kun je meer http requests afhandelen met dezelfde hoeveelheid database connecties. Eventueel kun SQL Relay inzetten om connectionpool management weg te halen bij de database server.

Daarnaast heb ik ook nergens beweert dat een singeton niet de correcte oplossing was. Ik corrigeerde alleen de opmerking van Altex dat een singleton ervoor zorgt dat er slechts 1 verbinding met de database is, want dat is incorrect. Het singleton pattern ervoor zorgt dat er slechts 1 instantie van een class is. En als de class on-demand verbinding met de database maakt en de betreffende webpagina volledig uit cache kan worden gehaald. Dan heeft PHP wel een instantie van de class aangemaakt, maar is er geen verbinding opgezet.

Maar op het moment dat je met singletons werkt is het niet meer nodig om de database handle (instance reference) door te geven aan elke class welke mogelijk iets met de database doen.

If it isn't broken, fix it until it is..


Acties:
  • 0 Henk 'm!

  • ikke007
  • Registratie: Juni 2001
  • Laatst online: 18-09 14:10
XxKr0n3xX schreef op woensdag 30 juli 2008 @ 19:57:
Ik ben al aan het rondkijken op de diverse links. Voor mijn pagina is 1 database connectie per gebruiker nodig omdat mensen hun eigen paginaatje krijgen binnen de webapp waar ze dingen kunnen uploaden aanpassen etc.
Dan snap ik imho niet waarom je aan een gebruiker class een database connection wilt meegeven. Een database connection geef je aan objecten die er iets mee moeten doen. Dat is in dit geval je gebruiker class niet.

Je gebruiker object is een laag om te toetsen of de persoon die momenteel de huidige pageview aanvraagt het recht heeft om dit te doen. Dit object is (utopisch) aangemaakt door je inlogpagina/class zodra deze een geldige login heeft herkend en opgeslagen in bv de sessie van de gebruiker. Het enige wat dit object moet doen is antwoord geven op vragen zoals 'mag ik dit doen'.

PHP:
1
2
3
4
5
6
7
//bijvoorbeeld met constanten
if(!$gebruiker->hasPermission(VIEW_PAGE_PERSONALSETTINGS)){
  //no rights to be here, show error message and goodbye
  exit(1);
}

//normal code goes here


Echter, zoals jij het schetst is je gebruiker.class.php gebruiker & gebruikersbeheerder in 1 class (waardoor je dus je databaseconnection nodig hebt om login/logout te registreren). Dit betekend dat je de rollen van objecten niet goed hebt uitgezocht en dus teveel functionaliteit in 1 class hebt gemaakt.

Verdiep je nog wat meer in het gebruik van objecten en hoe je deze goed definieert, want eigenlijk ligt je probleem dieper dan je zelf momenteel denkt.

Een correcte opzet van objecten in deze situatie zou zijn:
  • gebruikerBeheerder.class.php -> deze verwerkt inlogpogingen, maakt gebruiker objecten aan en logt deze weer uit
  • gebruiker.class.php -> het gebruiker object, welke enkel weet heeft van zichzelf (en zijn permissies)
  • database.class.php -> je database abstraction layer
  • sessie.class.php -> je sessie abstraction layer (voor dit voorbeeld nutteloos)
voorbeeld van gebruikerbeheerder
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
30
31
32
33
34
35
36
37
38
39
40
class gebruikerBeheerder{

  private $_fDatabaseConnection;

  public function __construct(DatabaseConnection $aDatabaseConnection){
    $this->_fDatabaseConnection = $aDatabaseConnection;
  }

  /**
  * Log user in
  * @param string $aUsername
  * @param string $aPassword
  * @return FALSE|Gebruiker False if not logged in
  */
  public function login($aUsername,$aPassword){
    static $preparedStatement;
    if(is_null($preparedStatement)){   
      //query is even kort & bondig, normaal zou je uiteraard de velden uitschrijven (toch?!)
      $preparedStatement = $this->_fDatabaseConnection->prepare("
        SELECT * 
        FROM gebruiker 
        WHERE gebruikersnaam = ? 
          AND password = ?
       ",array('text','text'));
      }
      $resultArray = $this->_fDatabaseConnection->execute($preparedStatement,array($aUsername,md5($aPassword)));
     if(is_null($resultArray)){
      return FALSE;
     }
     else{
       $result = new Gebruiker($resultArray);
       $_SESSION['user'] = $result;//schrijf user naar session om later terug te halen (niet opnieuw inte loggen)
       return $result;//geef user terug
     }
  }
  public function logout(Gebruiker $aUser){
    session_unregister('user');//gebruiker is bij volgende pageview niet meer ingelogt
    return true;
  }
}

[ Voor 37% gewijzigd door ikke007 op 31-07-2008 09:11 . Reden: voorbeeld ingevoegd ]

Lets remove all security labels and let the problem of stupidity solve itself


Acties:
  • 0 Henk 'm!

  • SchizoDuckie
  • Registratie: April 2001
  • Laatst online: 18-02 23:12

SchizoDuckie

Kwaak

XxKr0n3xX schreef op woensdag 30 juli 2008 @ 21:13:
[...]


Queries uit de code weg te halen dus de code schoner maken en de database laag scheiden van de code laag. Normaliter zou je dit in je model kunnen zetten dat ben ik me bewust maar ik vond het wel een mooie oplossing die de code mooi schoon en overzichtelijk houdt.
Ik snap eerlijk gezegd nog steeds niet echt wat het voordeel is? en waar je het dan zou gebruiken? Doe een call procedure in plaats van een select/insert oid :? Dat is toch een crime om te ondehrouden ?

[ Voor 3% gewijzigd door SchizoDuckie op 31-07-2008 10:23 ]

Stop uploading passwords to Github!

Pagina: 1