Scriptorama.nl

Header image showing a keyboard, mouse, laptop and books on design patterns

Een blik op MySQLi (Deel I)

Sinds PHP 5 is er een nieuwe extensie voor het gebruik met MySQL 4.1 tot 5.0: de MySQLi extensie. Deze versies van MySQL bevatten nieuwe features op verschillende vlakken en waar van toepassing biedt deze extensie daar ondersteuning voor. Denk aan dingen als SSL connecties, prepared statements, en sinds MySQL 5.0 ook stored procedures. Deze korte reeks bekijkt de mogelijkheden van MySQLi tov die van de oude MySQL extensie. Dit eerste artikel uit de reeks kijkt naar hoe je in met MySQLi de standaard dingen kunt doen die je met de MySQL extensie gewend bent.

Smaken verschillen

Het eerste verschil met de normale mysql extensie is dat de extensie in feite in 2 smaken komt: een procedurele, zoals je gewend was in PHP4 en een object georiënteerde smaak waarbij elke connectie en query resultaat een apart object is. Aangezien ik persoonlijk wel van de objecten hou, zal ik me dan ook richten op die smaak van MySQLi.

En hup! Van z'n 4 naar z'n 5!

Voor de standaard MySQL dingen gebruikte je in PHP 4 over het algemeen 7 functies:

  1. mysql_connect() om een connectie te maken
  2. mysql_select_db() om de database te selecteren
  3. mysql_query() om een query uit te voeren
  4. mysql_num_rows() om het aantal rijen in het resultaat te bepalen
  5. mysql_fetch_assoc() of een andere mysql_fetch_*() variant
  6. mysql_free_result() om de resultaten vrij te geven
  7. mysql_close() om de connectie weer te sluiten

Aangezien we nu een MySQLi object gebruiken zal het er allemaal net iets anders uitzien maar omdat de mannen van PHP zo aardig zijn geweest om de methodes in MySQLi vergelijkbare namen te geven als de functies in PHP4 zul je zien dat het allemaal best nog op elkaar lijkt:

PHP:
  1. $link = new MySQLi('localhost', 'test', 'test');
  2. $link->select_db('scriptorama');

Je kunt echter ook direct de database naam doorgeven aan de constructor:

PHP:
  1. $link = new MySQLi('localhost', 'test', 'test', 'scriptorama');

Mag ik van jou.....

We zullen later zien dat MySQLi meerdere methodes biedt om queries uit te voeren. In dit artikel beperken we ons tot de methode zoals je deze kent van PHP 4:

PHP:
  1. $link = new MySQLi('localhost', 'test', 'test', 'scriptorama');
  2. $result = $link->query("SELECT id, titel FROM guestbook");
  3.  
  4. while ($row = $result->fetch_assoc($res)) {
  5.   echo '#', $row['id'], ' heeft als titel: "', $row['titel'], '"<br />';
  6. }
  7.  
  8. // geef het resultaat vrij
  9. $result->close();
  10.  
  11. // sluit de connectie
  12. $link->close();

Gaat het weer een beetje? Meneer MySQL?

Een connectie kan mislukken gaan en een query kan in de soep lopen door een simpele fout, kortom: we moeten kijken of alles goed is gegaan. Om te controleren of de connectie goed is gelopen zullen we een kleine omleiding van de object georiëteerde highway moeten nemen en de functies mysqli_connect_errno() en mysqli_connect_error() gebruiken. Deze worden niet direct door het MySQLi object ondersteund:

PHP:
  1. $link = new MySQLi('localhost', 'test', 'test', 'scriptorama');
  2.  
  3. // mysql_connect_errno() retourneert 0 als er geen fouten zijn
  4. if (!$link || mysqli_connect_errno() != 0) {
  5.   echo "Er is iets fout gegaan: ", mysql_connect_error();
  6.   exit;
  7. }

Om te controleren of er iets fout is gegaan bij een query kun je kijken of MySQLi::query() FALSE heeft geretourneerd. Foutmeldingen kun je dan vervolgens vinden in de property MySQLI::error zoals het volgende voorbeeld toont:

PHP:
  1. $link = new MySQLi('localhost', 'test', 'test', 'scriptorama');
  2.  
  3. // mysql_connect_errno() retourneert 0 als er geen fouten zijn
  4. if (!$link || mysqli_connect_errno() != 0) {
  5.   echo "Er is iets fout gegaan: ", mysql_connect_error();
  6.   exit;
  7. }
  8.  
  9. // We hebben de tabelnaam fout geschreven
  10. $result = $link->query("SELECT * FROM gestboek");
  11.  
  12. if (!$result) {
  13.   echo "Helaas, er is een fout opgetreden in de database<br />";
  14.   echo "De foutmelding was: ", $link->error, "<br />";
  15. }
  16.  
  17. /* $result is FALSE en geen
  18. * result object en dus hoeven we die
  19. * te sluiten. De connectie echter wel: */
  20.  
  21. $link->close();

Opmerking:Uit usability en veiligheids overwegingen zou je de foutmelding eigenlijk niet in z'n geheel moeten tonen. In principe heeft niemand behalve jij iets aan die gegevens en het is niet nodig om eventuele kwaadwillenden de details van jouw database structuur te geven

Conclusie

Zoals je ziet kun je met MySQLi op bijna dezelfde manier, soms zelfs iets makkelijker, gegevens uit MySQL halen. In de rest van deze reeks zullen we verder kijken naar de extra mogelijkheden die de extensie biedt.

Reageer ook!

Als je een onstabiele database connectie gebruikt naar een remote server zou je het volgende principe kunnen gebruiken:

PHP:
  1. class mysqlidb
  2. {
  3.   function connectDB() {
  4.     $this->mysqli = new mysqli(
  5.       $this->_config['dbhost'],
  6.       $this->_config['dbuser'],
  7.       $this->_config['dbpass'],
  8.       $this->_config['dbname']
  9.     );
  10.    
  11.     if(mysqli_connect_errno()) {
  12.       $this->handleError("MYSQLCONNECT: failed");
  13.     }
  14.    
  15.     $this->eventLog("MYSQLCONNECT success", 0);
  16.   }
  17.  
  18.   function query($sql)
  19.   {
  20.     if(!is_object($this->mysqli)) {
  21.       $this->connectDB();
  22.     }
  23.    
  24.     if($this->mysqli->ping()) {
  25.       $this->res = $this->mysqli->query($sql);
  26.     } else {
  27.       $this->connectDB();
  28.       $this->query($sql)
  29.     }
  30.   }
  31. }

Kan allemaal wel beter, want nu blijft ie tot in den eeuwigheid proberen te connecten, maar het gaat om het idee.

Dat is natuurlijk snel op te lossen met een retry-teller mechanisme.

PHP:
  1. private $maxRetries = 5;
  2. private $numRetries = 0;
  3.  
  4. function query($sql, $isRetry = false)
  5. {
  6.   if ( !$isRetry )
  7.   {
  8.     $this->numRetries = 0;
  9.   }
  10.  
  11.   if ($this->_mysqli->ping())
  12.   {
  13.     $this->res = $this->mysqli->query($sql);
  14.   } else {
  15.     if ($isRetry && $this->numRetries <$this->maxRetries)
  16.     {
  17.        $this->numRetries++;
  18.        $this->connectDB();
  19.        $this->query($sql, true);
  20.     }
  21.   }
  22. }

[...] Een blik op MySQLi I - Standaard werk [...]

[...] MySQLi I - Een introductie tot MySQLi [...]

Als ik op deze manier een connectie probeer te maken krijg ik de volgende error:

Fatal error: Cannot instantiate non-existent class: mysqli

Ik gebruik MySQL 5 met PHP5.

Enig idee wat er fout gaat?

Kijk eens of de mysqli extensie wel geladen is met behulp van de functie phpinfo(). Zo niet, dan zul je deze in php.ini moeten activeren.