login  Naam:   Wachtwoord: 
Registreer je!
 Forum

PDO::FETCH_SERIALIZE kapot?

Offline Thomas - 01/07/2014 16:16 (laatste wijziging 01/07/2014 16:52)
Avatar van ThomasModerator Ik ben mij aan het verdiepen in PDO en probeer PDO::FETCH_SERIALIZE aan de praat te krijgen op mijn WAMP server (PHP 5.3.8, MySQL 5.5.16). Over deze fetch-methode is weinig gedocumenteerd. Van PHP.net:
Citaat:
As PDO::FETCH_INTO but object is provided as a serialized string. Available since PHP 5.1.0. Since PHP 5.3.0 the class constructor is never called if this flag is set.
Maar dat snijdt niet echt hout want als je in de PDOStatement::setFetchMode() methode enkel PDO::FETCH_SERIALIZE gebruikt krijg ik de volgende foutmelding:
Citaat:
SQLSTATE[HY000]: General error: PDO::FETCH_SERIALIZE can only be used together with PDO::FETCH_CLASS
Vervolgens loop je tegen de volgende mysterieuze foutmelding aan:
Citaat:
SQLSTATE[HY000]: General error: cannot unserialize class
Via een oude bug kwam ik erachter dat de klasse van het te serialiseren object (blijkbaar, dit werd nergens duidelijk) de Serializable interface moet implementeren. Dit houdt in dat je de publieke methodes serialize() en unserialize($data) moet implementeren.

En dan nog lijkt dat kreng niet geserialiseerd te worden , ik krijg gewoon een object terug (of mis ik nu iets?).

Daarnaast lijkt deze fetch-methode het volgende bizarre gedrag te vertonen: de eerste kolom van mijn query-resultaat verdwijnt (wordt null)! Als tevens de eerste kolom numeriek is, en ik de resultaatkolommen via de magic method __set() in één class-property wil opslaan krijg ik de volgende foutmelding:
Citaat:
Warning: Cannot use a scalar value as an array
Tenzij ik een dummy-kolom in mijn SELECT-query stop (die dus verloren gaat) krijg ik dit niet aan de praat.

Om nog maar te zwijgen van serialize() en unserialize() want die zijn niet multibyte-aware.

Iemand hier ervaring mee? Tijd voor een PHP-upgrade?

Alternatieve oplossing: vermijd het gebruik van PDO::FETCH_SERIALIZE, serialiseer je objecten zelf, en dan bij voorkeur met json_encode() en json_decode().

Uiteindelijke code van een semi-werkend voorbeeld (noot: de config tabel is een simpele tabel met 3 kolommen: id(PK), _key(uniek), _value):

  1. <?php
  2. header('Content-Type: text/html; charset=UTF-8');
  3.  
  4. class Config implements Serializable
  5. {
  6. protected $p;
  7.  
  8. // will not be called after PHP 5.3.0
  9. /*
  10.   public function __construct() {
  11.   $this->p = array();
  12.   }
  13.   */
  14.  
  15. public function serialize() {
  16. $this->p['serialize_called'] = true;
  17. return json_encode($this->p);
  18. }
  19.  
  20. public function unserialize($data) {
  21. $this->p = json_decode($data);
  22. $this->p['unserialize_called'] = true;
  23. }
  24.  
  25. public function __set($k, $v) {
  26. $this->p[$k] = $v;
  27. }
  28. } // class
  29.  
  30. try {
  31. switch ($_SERVER['HTTP_HOST']) {
  32. case 'test.local':
  33. $dsn = 'mysql:dbname=test;host=127.0.0.1;charset=utf8';
  34. $username = 'test';
  35. $password = 'test';
  36. break;
  37.  
  38. default:
  39. die('unknown host');
  40. }
  41. $pdo = new PDO($dsn, $username, $password, array(
  42. PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
  43. PDO::ATTR_PERSISTENT => false,
  44. PDO::ATTR_EMULATE_PREPARES => true,
  45. PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
  46. PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
  47. ));
  48.  
  49. /* @var $ps PDOStatement */
  50. $ps = $pdo->query("SELECT 'rofl' AS lol, _key, _value FROM config WHERE id = 1");
  51. $ps->setFetchMode(PDO::FETCH_CLASS|PDO::FETCH_SERIALIZE, 'Config');
  52. $config = $ps->fetch();
  53. $ps->closeCursor();
  54.  
  55. var_dump($config);
  56. } catch (Exception $e) {
  57. echo $e->getMessage();
  58. }
  59. ?>


noot: die eerste kolom komt dus niet terug in $config.
noot: het lijkt niet uit te maken of je al dan niet gebruik maakt van een __set() methode, of je nu fetch() of fetchAll() gebruikt, of prepare() + execute() in plaats van query(), en ook connectie-opties lijken niet van invloed te zijn.

Output:
  1. object(Config)[3]
  2. protected 'p' =>
  3. array
  4. 'unserialize_called' => boolean true
  5. '_key' => string 'first' (length=5)
  6. '_value' => string 'one' (length=3)


Mis ik iets? Doe ik iets verkeerd? Ik snap er geen drol van lol.

EDIT: misschien is mijn uitgangspunt verkeerd en moet ik uitgaan van geserialiseerde data in mijn database? Dan is het op zich wel logisch dat PDO één resultaat-kolom verwacht, deze wordt dan waarschijnlijk automagisch terugvertaald via unserialize()?

0 antwoorden

Gesponsorde links
Er zijn nog geen reacties op dit bericht.
Je moet ingelogd zijn om een reactie te kunnen posten.
Actieve forumberichten
© 2002-2024 Sitemasters.be - Regels - Laadtijd: 0.271s