1. #1
    sarnath's Avatar
    Registered
    07/11/03
    Location
    Bree
    Posts
    6,239
    iTrader
    158 (99%)
    Mentioned
    0 Post(s)
    Reputation
    0/0

    php-oop met database (mysqli)

    Ik maak nu al een tijdje gebruik van de objectgeoriënteerde manier van werken met mysqli om mijn data af te handelen.

    Nu zou ik echter een stap verder willen gaan en met classes gaan werken gezien ik totnutoe altijd vooral proceduraal gewerkt heb.

    Ik heb al heel wat opzoekwerk gedaan op google, maar ik vind verbazend weinig echt nuttige zaken terug behalve misschien deze:WebmasterCity - Scripts - OOP Gastenboek

    echter heb ik een paar opmerkingen over dit script, er wordt bijvoorbeeld een database adapter in de class Reactie gestoken terwijl dit volgens mij beter gescheiden gehouden wordt?
    Daarnaast wordt dan daarom een reactie opgeslagen op volgende manier: $reactie->opslaan() terwijl het mij logischer lijkt dat je een object aan je dataklasse doorgeeft en deze gebruikt om je gegevens op te slaan, dus in de aard van $dataReacties = new DataReacties();
    $dataReacties.insertRectie($reactie);

    Ik heb daarom eens een scriptje uitgewerkt waarbij ik gebruik maak van aparte objecten, dataclasses en een mysqli connectie klasse waarop ik graag wil verderbouwen, maar ik had er graag eens jullie mening over gehad of mijn werkwijze correct is (het werkt in ieder geval )

    Code:
    <?php
    class Database{
    	private $connection;
    	
    	public function maak_verbinding($host, $gebruikersnaam, $wachtwoord, $naam){
    		//connectie maken
    		$this->connection = new mysqli($host,$gebruikersnaam,$wachtwoord,$naam);
    		if (mysqli_connect_errno()) {
    			printf("Kan niet connecteren met MySQL Server. Errorcode: %s <br />", mysqli_connect_error());
    			exit;
    		}
    		
    		//encoding op UTF-8 zetten
    		$this->connection->query("SET NAMES 'utf8'");
    	}
    	
    	public function get_connection(){
    		return $this->connection;
    	}
    	
    	public function sluit_verbinding(){
    		$connection->close();
    	}
    }
    ?>

    Code:
    <?php
    class DataNieuws{
    	private $database;
    	
    	public function __construct(Database $database) 
    	{ 
    		$this->database = $database;
    	}
    	
    	public function nieuws_toevoegen(Nieuwsbericht $nieuwsbericht) 
    	{
    		$query_insert_nieuws = "insert into nieuws(titel,bericht,datum,gebruiker) values(?,?,?,?)";
    
    		if ($stmt = $this->database->get_connection()->prepare($query_insert_nieuws)) {
    			$stmt->bind_param('ssss',$nieuwsbericht->titel,$nieuwsbericht->bericht,$nieuwsbericht->datum,$nieuwsbericht->gebruikersnaam);
    			$stmt->execute();
    			$stmt->store_result();
    			if(!($stmt->affected_rows == 1)){
    				echo "Er heeft zich een fout voorgedaan bij het toevoegen van het nieuwsbericht : " . $stmt->error . "<br /><br />";
    			}else{
    				echo "opgeslagen.<br /><br />";
    			}
    							
    			$stmt->close();
    		}else{
    			echo "Er heeft zich een fout voorgedaan bij het toevoegen van het product : " . $stmt->error . "<br /><br />";
    		} 
    	}
    	
    	public function get_nieuwsbericht($id){
    		$query = "select titel,bericht,datum,gebruiker from nieuws where nieuwsID = ?";
    		if ($stmt = $this->database->get_connection()->prepare($query)) {
    			$stmt->bind_param('i',$id);
    			$stmt->execute();
    			$stmt->bind_result($titel,$bericht,$datum,$gebruikersnaam);		
    			$stmt->store_result();
    			$stmt->fetch();
    											
    			if(($stmt->num_rows) == 1){
    				return new Nieuwsbericht($titel,$bericht,$datum,$gebruikersnaam);
    			}else{
    				echo 'Het nieuwsbericht werd niet teruggevonden.';
    			}
    			$stmt->close();
    		}else{
    			echo "Er heeft zich een fout voorgedaan bij het toevoegen van het product : " . $stmt->error . "<br /><br />";
    		} 
    	}
    	
    	public function get_nieuwsberichten($aantal){
    		$query = "select titel,bericht,datum,gebruiker from nieuws order by datum desc LIMIT ?";
    		if ($stmt = $this->database->get_connection()->prepare($query)) {
    			$stmt->bind_param('i',$aantal);
    			$stmt->execute();
    			$stmt->bind_result($titel,$bericht,$datum,$gebruikersnaam);		
    			$stmt->store_result();
    			if(($stmt->num_rows) > 0){
    				while ($stmt->fetch()) {
    					$nieuwsberichten = new Nieuwsbericht($titel,$bericht,$datum,$gebruikersnaam);
    				}
    				return $nieuwsberichten;
    			}
    			$stmt->close();
    		}else{
    			echo "Er heeft zich een fout voorgedaan bij het ophalen van de nieuwsberichten : " . $stmt->error . "<br /><br />";
    		} 
    	}
    }
    ?>


    Code:
    <?php
    	class Nieuwsbericht{
    		public $titel;
    		public $bericht;
    		public $datum;
    		public $gebruikersnaam;
    		
    		//constructor
    		public function __construct($titel,$bericht,$datum,$gebruikersnaam,$datanieuws=""){
    			$this->titel = $titel;
    			$this->bericht = $bericht;
    			$this->datum = $datum;
    			$this->gebruikersnaam = $gebruikersnaam;
    			$this->datanieuws = $datanieuws;
    			return;
    		}
    		
    		//titel
    		public function setTitel($titel){
    			$this->$titel = $titel;
    			return;
    		}
    		
    		public function getTitel(){
    			return $this->titel;
    		}
    		
    		//bericht
    		public function setBericht($bericht){
    			$this->$bericht = $bericht;
    			return;
    		}
    		
    		public function getBericht(){
    			return $this->bericht;
    		}
    		
    		//datum
    		public function setDatum($datum){
    			$this->$datum = $datum;
    			return;
    		}
    		
    		public function getDatum(){
    			return $this->datum;
    		}
    		
    		//gebruikersnaam
    		public function setGebruikersnaam($gebruikersnaam){
    			$this->$gebruikersnaam = $gebruikersnaam;
    			return;
    		}
    		
    		public function getGebruikersnaam(){
    			return $this->gebruikersnaam;
    		}
    	}
    ?>
    uitvoeren:

    Code:
    <?php
    //classes importeren
    require_once("Database.php");
    require_once("DataNieuws.php");
    require_once("Nieuwsbericht.php");
    //opslaan
    $db = new Database();
    $db->maak_verbinding('localhost', 'user', 'pass', 'dbname');
    $dataNieuws = new DataNieuws($db);
    $nieuwsbericht = new Nieuwsbericht("test","testbericht","2010-10-01","testgebruiker");
    $dataNieuws->nieuws_toevoegen($nieuwsbericht);
    //tonen
    $db = new Database();
    $db->maak_verbinding('localhost', 'root', 'bartbart', 'testclasses');
    $dataNieuws = new DataNieuws($db);
    $nieuwsbericht = $dataNieuws->get_nieuwsbericht(1);
    echo $nieuwsbericht->titel;
    ?>
    webdeveloper / gamer
    no votes  

  2. #2

    Registered
    09/08/05
    Location
    Kieskring BHV
    Posts
    1,683
    iTrader
    5 (100%)
    Mentioned
    0 Post(s)
    Reputation
    1/22
    Waarom zie ik in PHP altijd public datamembers terwijl het in andere talen de gewoonte is ze private te maken en met getters en setters te werken?

    Verder lijkt de scheiding van de lagen mij wel inorde. Ik ben zelf wel meer geneigd om de methoden van DataNieuws bij Nieuwsbericht te plakken.

    Eventueel van u database een singleton maken?

    /edit: ik zie net dat jij public datamembers én getters en setters gebruikt, is toch nergens voor nodig?
    Last edited by sanzo; 10-09-2010 at 03:04.
    no votes  

  3. #3
    sarnath's Avatar
    Registered
    07/11/03
    Location
    Bree
    Posts
    6,239
    iTrader
    158 (99%)
    Mentioned
    0 Post(s)
    Reputation
    0/0
    @eerste opmerking, idd goede vraag, in java en .NET gebruik ik idd private en getters en setters, in php kan je in ieder geval gewoon de var aanroepen ipv via de getter, maar het is mss beter om via de getter te werken, zou daar niet echt op kunnen antwoorden wat het beste is.

    @ je edit, je hebt volledig gelijk, maar in mijn script gebruik ik nog beiden door elkaar, gewoonweg om de verschillende mogelijkheden uit te proberen, in productie zal ik sowieso nog gaan opsplitsen, dus ofwel met public members werken ofwel met getters en setters.

    singleton kan ik eventueel doen ja.

    Bedankt voor je opmerkingen alvast
    webdeveloper / gamer
    no votes  

  4. #4
    Tyfius's Avatar
    Registered
    01/09/02
    Location
    Peutie
    Posts
    7,664
    iTrader
    0
    Mentioned
    4 Post(s)
    Reputation
    13/105
    Van die database kan je inderdaad misschien best een singleton maken, of je moet ze overal aan gaan meegeven. Dan is de keuze snel gemaakt.

    Getters en setters zijn in de meeste gevallen overroepen naar mijn mening. Als ze effectief iets moeten doen (validatie, andere dingen setten en dergelijke meer), dan moet je ze gebruiken, maar meestal staan ze garant voor onnodig veel overbodige code. Neem nu onderstaand (veel voorkomend) voorbeeld:
    Code:
    class Foo {
      private $_foo;
    
      public GetFoo() { return $_foo; }
      public SetFoo($foo) { $_foo = $foo; }
    }
    Hier ga ik bijna altijd gewoon een public variabele van maken. Zolang je maar consistent en duidelijk bent is er niets mis mee.

    Vandaar dat ze in .NET 3.0 ook de automatic properties geïntroduceerd hebben. Kan je nog iets van scheiding doen zonder effectief zelf een hoop extra code te gaan schrijven.

    Just my 2 cents.
    Vanaf nu gaan we verder op BeyondGaming!
    In deze thread wordt uitgelegd hoe je jouw account kan migreren.
    no votes  

  5. #5
    sarnath's Avatar
    Registered
    07/11/03
    Location
    Bree
    Posts
    6,239
    iTrader
    158 (99%)
    Mentioned
    0 Post(s)
    Reputation
    0/0
    Quote Originally Posted by Tyfius View Post
    This quote is hidden because you are ignoring this member. Show
    Van die database kan je inderdaad misschien best een singleton maken, of je moet ze overal aan gaan meegeven. Dan is de keuze snel gemaakt.

    Getters en setters zijn in de meeste gevallen overroepen naar mijn mening. Als ze effectief iets moeten doen (validatie, andere dingen setten en dergelijke meer), dan moet je ze gebruiken, maar meestal staan ze garant voor onnodig veel overbodige code. Neem nu onderstaand (veel voorkomend) voorbeeld:
    Code:
    class Foo {
      private $_foo;
    
      public GetFoo() { return $_foo; }
      public SetFoo($foo) { $_foo = $foo; }
    }
    Hier ga ik bijna altijd gewoon een public variabele van maken. Zolang je maar consistent en duidelijk bent is er niets mis mee.

    Vandaar dat ze in .NET 3.0 ook de automatic properties geïntroduceerd hebben. Kan je nog iets van scheiding doen zonder effectief zelf een hoop extra code te gaan schrijven.

    Just my 2 cents.
    Idd, die getters en setters zijn enorm veel typwerk en als het niet hoeft mss beter vermijden.
    Automatic properties in .NET 3.0 is idd een prachtige vooruitgang.

    Bedankt voor je tips
    webdeveloper / gamer
    no votes  

  6. #6
    dJeez's Avatar
    Registered
    17/07/02
    Location
    Sol System
    Posts
    10,064
    iTrader
    1 (100%)
    Mentioned
    0 Post(s)
    Reputation
    27/78
    Quote Originally Posted by sarnath View Post
    This quote is hidden because you are ignoring this member. Show
    Idd, die getters en setters zijn enorm veel typwerk
    Euh... Gewoon je private datamembers definiëren, en dan via code completion de getters en setters laten creëren, dat is nu eens geen werk. Gebruik dus eerst maar een deftige IDE (NetBeans met PHP support doet het wel goed, en vind ik ook iets sneller werken dan Eclipse PDT).

    Wat mij persoonlijk overigens wel stoort is dat je foutmeldingen zit te echo-en vanuit je model, en ook dat je geen coding convention gebruikt in je code (de ene keer is 't camel case, de andere keer lowercase met underscores - PHP is op zich al inconsistent genoeg ). Eigenlijk zou je misschien ineens de stap naar ORM moeten zetten. Uit de aanpak van vb. Propel kan je enorm veel leren, dat lijkt mij als tijdsbesteding ook nuttiger dan zelf het wiel opnieuw te proberen uitvinden. En wat de coding conventions betreft, persoonlijk vind ik die van het Zend Framework wel aangenaam werken (http://framework.zend.com/manual/en/...-standard.html).
    Last edited by dJeez; 10-09-2010 at 23:21.
    PSN: dJeezBE - Delicious bookmarks
    Disclaimer: I am currently suffering from severe CSD (Compulsive Sarcasm Disorder). - L'onion fait la farce - Facile largire de alieno
    Pastafarian by choice
    no votes  

  7. #7
    sarnath's Avatar
    Registered
    07/11/03
    Location
    Bree
    Posts
    6,239
    iTrader
    158 (99%)
    Mentioned
    0 Post(s)
    Reputation
    0/0
    idd, voor java en dergelijke gebruik ik eclipse, voor php gewoon JEdit, mss handiger om idd een IDE te gebruiken

    camelcase en throwen van exceptions doe ik echter wel bij java en .NET dus waarom ik het hier niet heb gedaan is puur uit snel een voorbeeld ineen te willen stampen, maar ik ga er inderdaad aandacht aan moeten besteden om het overzichtelijk te houden en niet altijd te snel willen zijn

    Propel en zend heb ik al van gehoord en ga deze zeker eens bestuderen.
    Bedankt voor de tips!
    Last edited by sarnath; 12-09-2010 at 14:17.
    webdeveloper / gamer
    no votes  

  8. #8
    sarnath's Avatar
    Registered
    07/11/03
    Location
    Bree
    Posts
    6,239
    iTrader
    158 (99%)
    Mentioned
    0 Post(s)
    Reputation
    0/0
    Quote Originally Posted by Tyfius View Post
    This quote is hidden because you are ignoring this member. Show
    Van die database kan je inderdaad misschien best een singleton maken, of je moet ze overal aan gaan meegeven. Dan is de keuze snel gemaakt.
    Mijn huidig script is zo goed als af en heb van de database een singleton gemaakt. Ik snap wel niet goed wat je bedoelt met dat ik het nu overal moet gaan meegeven.
    Is dat niet nog steeds zo met een singleton en is een singleton niet gewoon bedoeld zodat ik slechts één instantie van het database object hoef te maken en zo meer performantie heb?
    webdeveloper / gamer
    no votes  

  9. #9
    Tyfius's Avatar
    Registered
    01/09/02
    Location
    Peutie
    Posts
    7,664
    iTrader
    0
    Mentioned
    4 Post(s)
    Reputation
    13/105
    Quote Originally Posted by sarnath View Post
    This quote is hidden because you are ignoring this member. Show
    Mijn huidig script is zo goed als af en heb van de database een singleton gemaakt. Ik snap wel niet goed wat je bedoelt met dat ik het nu overal moet gaan meegeven.
    Is dat niet nog steeds zo met een singleton en is een singleton niet gewoon bedoeld zodat ik slechts één instantie van het database object hoef te maken en zo meer performantie heb?
    Met een singleton moet je niets meegeven. Als je geen singleton gebruikt moet je het overal aan gaan doorgeven.
    Vanaf nu gaan we verder op BeyondGaming!
    In deze thread wordt uitgelegd hoe je jouw account kan migreren.
    no votes  

  10. #10
    sarnath's Avatar
    Registered
    07/11/03
    Location
    Bree
    Posts
    6,239
    iTrader
    158 (99%)
    Mentioned
    0 Post(s)
    Reputation
    0/0
    Sorry, maar ik snap nog steeds niet wat je wil zeggen, stel dat ik mijn singletonclass gebruik:

    Code:
    <?php
    class Database
    {
    	private $connection;
    	private static $m_pInstance;
    
    	private function __construct() 
    	{ 
    		echo "Constructor called<br />\n"; 
    	}
    	
    	public function makeConnection($host, $gebruikersnaam, $wachtwoord, $naam){
    		//connectie maken
    		$this->connection = new mysqli($host,$gebruikersnaam,$wachtwoord,$naam);
    		if (mysqli_connect_errno()) {
    			printf("Kan niet connecteren met MySQL Server. Errorcode: %s <br />", mysqli_connect_error());
    			exit;
    		}
    		
    		//encoding op UTF-8 zetten
    		$this->connection->query("SET NAMES 'utf8'");
    	}
    	
    	public function getConnection(){
    		return $this->connection;
    	}
    	
    	public function closeConnection(){
    		$this->connection->close();
    	}
    
    	public static function getInstance()
    	{
    		if (!self::$m_pInstance)
    		{
    			self::$m_pInstance = new Database();
    		}
    
    		return self::$m_pInstance;
    	}	
    }
    ?>
    Dan roep ik deze zo op:

    Code:
    $db = Database::getInstance();
    $db->makeConnection('localhost', 'user', 'pass', 'dbname');
    $dataNieuws = new DataNieuws($db);
    ...
    in plaats van:

    Code:
    $db = new Database();
    $db->maakVerbinding('localhost', 'user', 'pass', 'dbname');
    $dataNieuws = new DataNieuws($db);
    Dus structureel blijft het hetzelfde, ik maak het object enkel anders aan, maar geef het evengoed door aan mijn data adapters.
    Het verschil is nu dat er slechts één instance van bestaat.

    of bedoel je dat ik dan echt zo moet oproepen:
    Database::getInstance()->getConnection()->prepare($query) in bijvoorbeeld mijn DataNieuws klasse en dus aan de constructor niks meer meegeef?
    Last edited by sarnath; 13-09-2010 at 13:38.
    webdeveloper / gamer
    no votes  

  11. #11
    Tyfius's Avatar
    Registered
    01/09/02
    Location
    Peutie
    Posts
    7,664
    iTrader
    0
    Mentioned
    4 Post(s)
    Reputation
    13/105
    Inderdaad. Als je een singleton gebruikt hoef je die database parameter niet mee te geven aan je DataNieuws klasse. Je kan die rechtstreeks aanspreken.
    Vanaf nu gaan we verder op BeyondGaming!
    In deze thread wordt uitgelegd hoe je jouw account kan migreren.
    no votes  

  12. #12
    sarnath's Avatar
    Registered
    07/11/03
    Location
    Bree
    Posts
    6,239
    iTrader
    158 (99%)
    Mentioned
    0 Post(s)
    Reputation
    0/0
    Quote Originally Posted by Tyfius View Post
    This quote is hidden because you are ignoring this member. Show
    Inderdaad. Als je een singleton gebruikt hoef je die database parameter niet mee te geven aan je DataNieuws klasse. Je kan die rechtstreeks aanspreken.
    Ok bedankt, wist niet dat je een singleton direct kon aanspreken, want ik lees nu op een aantal fora dat men daarom het gebruik van je database als singleton wil afraden omdat het niet veilig is, maar als ik telkens de connectie wel op en sluit lijkt me dat toch niet direct onveilig?

    Der zijn gewoon een aantal voorstanders en een aantal tegenstanders wat het natuurlijk wat verwarrender maakt of ik het nu al dan niet zou gebruiken
    webdeveloper / gamer
    no votes  

  13. #13
    dJeez's Avatar
    Registered
    17/07/02
    Location
    Sol System
    Posts
    10,064
    iTrader
    1 (100%)
    Mentioned
    0 Post(s)
    Reputation
    27/78
    Tjah, er zijn er enkelen die het gebruik van singletons zien als het teken des duivels en dat dan ook wensen te verbannen. Dat zijn dan doorgaans aanhangers van dependency injection. Maar om er wat dieper op in te gaan : unit testing bijvoorbeeld is bij het gebruiken van singletons nogal lastig (op z'n zachtst uitgedrukt), dat gaat inderdaad wel een pak makkelijker met dependency injection, aangezien dat je dan ook makkelijk een mock object kan gaan doorgeven.

    Voor meer info ivm unit testing en singletons/dependency injection, zie Testing Code That Uses Singletons.
    Last edited by dJeez; 14-09-2010 at 23:45.
    PSN: dJeezBE - Delicious bookmarks
    Disclaimer: I am currently suffering from severe CSD (Compulsive Sarcasm Disorder). - L'onion fait la farce - Facile largire de alieno
    Pastafarian by choice
    no votes  

  14. #14
    sarnath's Avatar
    Registered
    07/11/03
    Location
    Bree
    Posts
    6,239
    iTrader
    158 (99%)
    Mentioned
    0 Post(s)
    Reputation
    0/0
    Interessante artikels, ga ze volledig doornemen, bedankt
    webdeveloper / gamer
    no votes  

  15. #15
    dJeez's Avatar
    Registered
    17/07/02
    Location
    Sol System
    Posts
    10,064
    iTrader
    1 (100%)
    Mentioned
    0 Post(s)
    Reputation
    27/78
    Bekijk ook The Clean Code Talks - "Global State and Singletons" eens als je er de tijd voor kan vrijmaken.
    PSN: dJeezBE - Delicious bookmarks
    Disclaimer: I am currently suffering from severe CSD (Compulsive Sarcasm Disorder). - L'onion fait la farce - Facile largire de alieno
    Pastafarian by choice
    no votes  

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  

Log in

Log in