@@ -221,10 +221,82 @@ static char *dsn_from_uri(char *uri, char *buf, size_t buflen) /* {{{ */
221221}
222222/* }}} */
223223
224- /* {{{ */
225- PHP_METHOD (PDO , __construct )
224+ #define MAX_PDO_SUB_CLASSES 64
225+ static unsigned int number_of_pdo_driver_class_entries = 0 ;
226+ static pdo_driver_class_entry * pdo_driver_class_entries [MAX_PDO_SUB_CLASSES ];
227+
228+ // It would be possible remove this and roll it into the standard driver class entries
229+ // I chose not to do it at this time, as that would break existing PDO extensions
230+ zend_result pdo_register_driver_specific_class (pdo_driver_class_entry * driver_class_entry )
231+ {
232+ if (number_of_pdo_driver_class_entries >= MAX_PDO_SUB_CLASSES ) {
233+ return FAILURE ;
234+ }
235+
236+ pdo_driver_class_entries [number_of_pdo_driver_class_entries ] = driver_class_entry ;
237+ number_of_pdo_driver_class_entries += 1 ;
238+
239+ return SUCCESS ;
240+ }
241+
242+ static bool create_driver_specific_pdo_object (const char * driver_name , zend_class_entry * called_scope , zval * new_object )
243+ {
244+ zend_class_entry * ce_based_on_driver_name = NULL , * ce_based_on_called_object = NULL ;
245+
246+ for (int i = 0 ; i < number_of_pdo_driver_class_entries && (ce_based_on_driver_name == NULL || ce_based_on_called_object == NULL ); i ++ ) {
247+ pdo_driver_class_entry * driver_class_entry = pdo_driver_class_entries [i ];
248+
249+ if (strcmp (driver_class_entry -> driver_name , driver_name ) == 0 ) {
250+ ce_based_on_driver_name = driver_class_entry -> driver_ce ;
251+ }
252+
253+ if (called_scope != pdo_dbh_ce && instanceof_function (called_scope , driver_class_entry -> driver_ce )) {
254+ ce_based_on_called_object = called_scope ;
255+ }
256+ }
257+
258+ if (ce_based_on_called_object ) {
259+ if (ce_based_on_driver_name ) {
260+ if (instanceof_function (ce_based_on_called_object , ce_based_on_driver_name ) == false) {
261+ zend_throw_exception_ex (php_pdo_get_exception (), 0 ,
262+ "%s::connect() cannot be called when connecting to the \"%s\" driver, "
263+ "you must call either %s::connect() or PDO::connect() instead" ,
264+ ZSTR_VAL (called_scope -> name ), driver_name , ZSTR_VAL (ce_based_on_driver_name -> name ));
265+ return false;
266+ }
267+
268+ object_init_ex (new_object , ce_based_on_called_object );
269+ return true;
270+ } else {
271+ zend_throw_exception_ex (php_pdo_get_exception (), 0 ,
272+ "%s::connect() cannot be called when connecting to an unknown driver, "
273+ "you must call PDO::connect() instead" ,
274+ ZSTR_VAL (called_scope -> name ));
275+ return false;
276+ }
277+ }
278+
279+ if (ce_based_on_driver_name ) {
280+ if (called_scope != pdo_dbh_ce ) {
281+ zend_throw_exception_ex (php_pdo_get_exception (), 0 ,
282+ "%s::connect() cannot be called when connecting to the \"%s\" driver, "
283+ "you must call either %s::connect() or PDO::connect() instead" ,
284+ ZSTR_VAL (called_scope -> name ), driver_name , ZSTR_VAL (ce_based_on_driver_name -> name ));
285+ return false;
286+ }
287+
288+ // A specific driver implementation was called on PDO
289+ object_init_ex (new_object , ce_based_on_driver_name );
290+ } else {
291+ // No specific DB implementation found
292+ object_init_ex (new_object , called_scope );
293+ }
294+
295+ return true;
296+ }
297+
298+ static void internal_construct (INTERNAL_FUNCTION_PARAMETERS , zend_object * object , zend_class_entry * current_scope , zval * new_zval_object )
226299{
227- zval * object = ZEND_THIS ;
228300 pdo_dbh_t * dbh = NULL ;
229301 bool is_persistent = 0 ;
230302 char * data_source ;
@@ -291,7 +363,17 @@ PHP_METHOD(PDO, __construct)
291363 RETURN_THROWS ();
292364 }
293365
294- dbh = Z_PDO_DBH_P (object );
366+ if (new_zval_object != NULL ) {
367+ ZEND_ASSERT ((driver -> driver_name != NULL ) && "PDO driver name is null" );
368+ bool result = create_driver_specific_pdo_object (driver -> driver_name , current_scope , new_zval_object );
369+ if (!result ) {
370+ RETURN_THROWS ();
371+ }
372+
373+ dbh = Z_PDO_DBH_P (new_zval_object );
374+ } else {
375+ dbh = php_pdo_dbh_fetch_inner (object );
376+ }
295377
296378 /* is this supposed to be a persistent connection ? */
297379 if (options ) {
@@ -352,7 +434,7 @@ PHP_METHOD(PDO, __construct)
352434 if (pdbh ) {
353435 efree (dbh );
354436 /* switch over to the persistent one */
355- Z_PDO_OBJECT_P (object )-> inner = pdbh ;
437+ php_pdo_dbh_fetch_object (object )-> inner = pdbh ;
356438 pdbh -> refcount ++ ;
357439 dbh = pdbh ;
358440 }
@@ -432,6 +514,19 @@ PHP_METHOD(PDO, __construct)
432514 zend_throw_exception (pdo_exception_ce , "Constructor failed" , 0 );
433515 }
434516}
517+
518+ /* {{{ */
519+ PHP_METHOD (PDO , __construct )
520+ {
521+ internal_construct (INTERNAL_FUNCTION_PARAM_PASSTHRU , Z_OBJ (EX (This )), EX (This ).value .ce , NULL );
522+ }
523+ /* }}} */
524+
525+ /* {{{ */
526+ PHP_METHOD (PDO , connect )
527+ {
528+ internal_construct (INTERNAL_FUNCTION_PARAM_PASSTHRU , Z_OBJ (EX (This )), EX (This ).value .ce , return_value );
529+ }
435530/* }}} */
436531
437532static zval * pdo_stmt_instantiate (pdo_dbh_t * dbh , zval * object , zend_class_entry * dbstmt_ce , zval * ctor_args ) /* {{{ */
@@ -1334,6 +1429,8 @@ static HashTable *dbh_get_gc(zend_object *object, zval **gc_data, int *gc_count)
13341429}
13351430
13361431static zend_object_handlers pdo_dbh_object_handlers ;
1432+ static zend_object_handlers pdosqlite_dbh_object_handlers ;
1433+
13371434static void pdo_dbh_free_storage (zend_object * std );
13381435
13391436void pdo_dbh_init (int module_number )
@@ -1349,6 +1446,13 @@ void pdo_dbh_init(int module_number)
13491446 pdo_dbh_object_handlers .get_method = dbh_method_get ;
13501447 pdo_dbh_object_handlers .compare = zend_objects_not_comparable ;
13511448 pdo_dbh_object_handlers .get_gc = dbh_get_gc ;
1449+
1450+ memcpy (& pdosqlite_dbh_object_handlers , & std_object_handlers , sizeof (zend_object_handlers ));
1451+ pdosqlite_dbh_object_handlers .offset = XtOffsetOf (pdo_dbh_object_t , std );
1452+ pdosqlite_dbh_object_handlers .free_obj = pdo_dbh_free_storage ;
1453+ pdosqlite_dbh_object_handlers .get_method = dbh_method_get ;
1454+ pdosqlite_dbh_object_handlers .compare = zend_objects_not_comparable ;
1455+ pdosqlite_dbh_object_handlers .get_gc = dbh_get_gc ;
13521456}
13531457
13541458static void dbh_free (pdo_dbh_t * dbh , bool free_persistent )
0 commit comments