Skip to content

Commit 5feb9aa

Browse files
committed
ext/pdo: Refactor PDO::FETCH_CLASS to not rely on a FCI and use a HashTable for ctor_arg
1 parent ba964cf commit 5feb9aa

8 files changed

+209
-283
lines changed

ext/pdo/pdo_stmt.c

Lines changed: 174 additions & 221 deletions
Large diffs are not rendered by default.

ext/pdo/php_pdo_driver.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -612,13 +612,14 @@ struct _pdo_stmt_t {
612612
union {
613613
int column;
614614
struct {
615-
zval ctor_args; /* freed */
616-
zend_fcall_info_cache fcc;
617-
zend_fcall_info fci;
615+
zval dummy; /* This exists due to alignment reasons with fetch.into */
616+
HashTable *ctor_args;
618617
zend_class_entry *ce;
619618
} cls;
620619
struct {
621-
zval dummy; /* This exists due to alignment reasons with fetch.into and fetch.cls.ctor_args */
620+
zval dummy; /* This exists due to alignment reasons with fetch.into */
621+
HashTable *dummy_ht; /* This exists to prevent conflict with cls.ctor_args */
622+
zend_class_entry *dummy_ce; /* This exists to prevent conflict with cls.ce */
622623
zend_fcall_info_cache fcc;
623624
} func;
624625
zend_object *into;

ext/pdo/tests/pdo_fetch_class_basic.phpt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ $stmt->execute();
4848
var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'TestBase'));
4949

5050
$stmt->execute();
51-
var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'TestDerived', array(0)));
51+
$rowCounter = 0;
52+
var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'TestDerived', [&$rowCounter]));
5253

5354
?>
5455
--CLEAN--

ext/pdo/tests/pdo_fetch_class_by_ref_constructor.phpt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,14 @@ $db = PDOTest::factory();
4747
PDOTest::dropTableIfExists($db, "pdo_fetch_class_by_ref_ctor");
4848
?>
4949
--EXPECTF--
50+
Warning: TestByRefCtor::__construct(): Argument #1 ($str) must be passed by reference, value given in %s on line %d
5051
TestByRefCtor::__construct(aaaaaaaaaa, 1)
51-
TestByRefCtor::__construct(aaaaaaaaaaA, 2)
52-
TestByRefCtor::__construct(aaaaaaaaaaAB, 3)
52+
53+
Warning: TestByRefCtor::__construct(): Argument #1 ($str) must be passed by reference, value given in %s on line %d
54+
TestByRefCtor::__construct(aaaaaaaaaa, 2)
55+
56+
Warning: TestByRefCtor::__construct(): Argument #1 ($str) must be passed by reference, value given in %s on line %d
57+
TestByRefCtor::__construct(aaaaaaaaaa, 3)
5358
array(3) {
5459
[0]=>
5560
object(TestByRefCtor)#%d (3) {
@@ -67,7 +72,7 @@ array(3) {
6772
["val"]=>
6873
string(1) "B"
6974
["str":"TestByRefCtor":private]=>
70-
string(12) "aaaaaaaaaaAB"
75+
string(11) "aaaaaaaaaaB"
7176
}
7277
[2]=>
7378
object(TestByRefCtor)#%d (3) {
@@ -76,6 +81,6 @@ array(3) {
7681
["val"]=>
7782
string(1) "C"
7883
["str":"TestByRefCtor":private]=>
79-
string(13) "aaaaaaaaaaABC"
84+
string(11) "aaaaaaaaaaC"
8085
}
8186
}

ext/pdo/tests/pdo_fetch_class_ctor_with_named_arguments.phpt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,12 @@ $db = PDOTest::factory();
4444
PDOTest::dropTableIfExists($db, "pdo_fetch_class_ctor_named");
4545
?>
4646
--EXPECTF--
47-
Value of $a: My key is B
48-
Value of $b: My key is A
49-
Value of $a: My key is B
50-
Value of $b: My key is A
51-
Value of $a: My key is B
52-
Value of $b: My key is A
47+
Value of $a: My key is A
48+
Value of $b: My key is B
49+
Value of $a: My key is A
50+
Value of $b: My key is B
51+
Value of $a: My key is A
52+
Value of $b: My key is B
5353
array(3) {
5454
[0]=>
5555
object(TestBase)#%d (3) {

ext/pdo/tests/pdo_fetch_class_ctor_with_named_arguments_positional_after_named.phpt

Lines changed: 2 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -48,39 +48,5 @@ require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
4848
$db = PDOTest::factory();
4949
PDOTest::dropTableIfExists($db, "pdo_fetch_class_ctor_named_and_positional");
5050
?>
51-
--EXPECTF--
52-
Value of $a: My key is B
53-
Value of $b: No key
54-
Value of $a: My key is B
55-
Value of $b: No key
56-
Value of $a: My key is B
57-
Value of $b: No key
58-
array(3) {
59-
[0]=>
60-
object(TestBase)#%d (3) {
61-
["id"]=>
62-
string(1) "1"
63-
["val":protected]=>
64-
string(1) "A"
65-
["val2":"TestBase":private]=>
66-
string(2) "AA"
67-
}
68-
[1]=>
69-
object(TestBase)#%d (3) {
70-
["id"]=>
71-
string(1) "2"
72-
["val":protected]=>
73-
string(1) "B"
74-
["val2":"TestBase":private]=>
75-
string(2) "BB"
76-
}
77-
[2]=>
78-
object(TestBase)#%d (3) {
79-
["id"]=>
80-
string(1) "3"
81-
["val":protected]=>
82-
string(1) "C"
83-
["val2":"TestBase":private]=>
84-
string(2) "CC"
85-
}
86-
}
51+
--EXPECT--
52+
Error: Cannot use positional argument after named argument

ext/pdo/tests/pdo_stmt_class_ctor_errors.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,5 @@ $db = PDOTest::factory();
4747
PDOTest::dropTableIfExists($db, "pdo_fetch_all_class_ctor_error");
4848
?>
4949
--EXPECT--
50-
Error: User-supplied statement does not accept constructor arguments
51-
Error: User-supplied statement does not accept constructor arguments
50+
ValueError: PDOStatement::fetchAll(): Argument #3 must be empty when class provided in argument #2 ($class) does not have a constructor
51+
ValueError: PDOStatement::setFetchMode(): Argument #3 must be empty when class provided in argument #2 ($class) does not have a constructor

ext/pdo/tests/pdo_stmt_fetchobject_ctor_args.phpt

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,15 @@ class Bar {
4040
$stmt->execute();
4141
try {
4242
$obj = $stmt->fetchObject(Foo::class);
43-
} catch (ArgumentCountError $exception) {
44-
echo $exception->getMessage() . "\n";
43+
} catch (Throwable $e) {
44+
echo $e::class, ': ', $e->getMessage(), "\n";
4545
}
4646

4747
$stmt->execute();
4848
try {
4949
$obj = $stmt->fetchObject(Foo::class, []);
50-
} catch (ArgumentCountError $exception) {
51-
echo $exception->getMessage() . "\n";
50+
} catch (Throwable $e) {
51+
echo $e::class, ': ', $e->getMessage(), "\n";
5252
}
5353

5454
$stmt->execute();
@@ -66,8 +66,8 @@ var_dump($obj);
6666
try {
6767
$stmt->execute();
6868
$obj = $stmt->fetchObject(Bar::class, ["a" => 123]);
69-
} catch (Error $exception) {
70-
echo $exception->getMessage() . "\n";
69+
} catch (Throwable $e) {
70+
echo $e::class, ': ', $e->getMessage(), "\n";
7171
}
7272

7373
?>
@@ -78,8 +78,8 @@ $db = PDOTest::factory();
7878
PDOTest::dropTableIfExists($db, "pdo_stmt_fetchobject_ctor_args");
7979
?>
8080
--EXPECTF--
81-
Too few arguments to function Foo::__construct(), 0 passed and exactly 1 expected
82-
Too few arguments to function Foo::__construct(), 0 passed and exactly 1 expected
81+
ArgumentCountError: Too few arguments to function Foo::__construct(), 0 passed and exactly 1 expected
82+
ArgumentCountError: Too few arguments to function Foo::__construct(), 0 passed and exactly 1 expected
8383
object(Foo)#%d (2) {
8484
["a"]=>
8585
int(123)
@@ -94,4 +94,4 @@ object(Bar)#%d (1) {
9494
["id"]=>
9595
int(1)
9696
}
97-
User-supplied statement does not accept constructor arguments
97+
ValueError: PDOStatement::fetchObject(): Argument #2 ($constructorArgs) must be empty when class provided in argument #1 ($class) does not have a constructor

0 commit comments

Comments
 (0)