Skip to content

Commit 9283abc

Browse files
authored
ext/pdo: Rename and add tests for PDO::FETCH_CLASS fetch mode (#17526)
1 parent b60f9bf commit 9283abc

9 files changed

+429
-0
lines changed
File renamed without changes.
+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
--TEST--
2+
PDO Common: PDO::FETCH_CLASS with by-ref constructor and arg by value
3+
--EXTENSIONS--
4+
pdo
5+
--SKIPIF--
6+
<?php
7+
$dir = getenv('REDIR_TEST_DIR');
8+
if (false == $dir) die('skip no driver');
9+
require_once $dir . 'pdo_test.inc';
10+
PDOTest::skip();
11+
?>
12+
--FILE--
13+
<?php
14+
if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/');
15+
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
16+
$db = PDOTest::factory();
17+
18+
$db->exec('CREATE TABLE pdo_fetch_class_by_ref_ctor(id int NOT NULL PRIMARY KEY, val VARCHAR(10), val2 VARCHAR(10))');
19+
$db->exec("INSERT INTO pdo_fetch_class_by_ref_ctor VALUES(1, 'A', 'AA')");
20+
$db->exec("INSERT INTO pdo_fetch_class_by_ref_ctor VALUES(2, 'B', 'BB')");
21+
$db->exec("INSERT INTO pdo_fetch_class_by_ref_ctor VALUES(3, 'C', 'CC')");
22+
$stmt = $db->prepare('SELECT id, val FROM pdo_fetch_class_by_ref_ctor');
23+
24+
class TestByRefCtor
25+
{
26+
public $id;
27+
public $val;
28+
private $str;
29+
30+
public function __construct(string &$str)
31+
{
32+
echo __METHOD__ . "($str, {$this->id})\n";
33+
$str .= $this->val;
34+
$this->str = $str;
35+
}
36+
}
37+
38+
$stmt->execute();
39+
// Use of random_int(10,10) is to defeat SCCP
40+
var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'TestByRefCtor', [str_repeat('a', random_int(10,10))]));
41+
42+
?>
43+
--CLEAN--
44+
<?php
45+
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
46+
$db = PDOTest::factory();
47+
PDOTest::dropTableIfExists($db, "pdo_fetch_class_by_ref_ctor");
48+
?>
49+
--EXPECTF--
50+
TestByRefCtor::__construct(aaaaaaaaaa, 1)
51+
TestByRefCtor::__construct(aaaaaaaaaaA, 2)
52+
TestByRefCtor::__construct(aaaaaaaaaaAB, 3)
53+
array(3) {
54+
[0]=>
55+
object(TestByRefCtor)#%d (3) {
56+
["id"]=>
57+
string(1) "1"
58+
["val"]=>
59+
string(1) "A"
60+
["str":"TestByRefCtor":private]=>
61+
string(11) "aaaaaaaaaaA"
62+
}
63+
[1]=>
64+
object(TestByRefCtor)#%d (3) {
65+
["id"]=>
66+
string(1) "2"
67+
["val"]=>
68+
string(1) "B"
69+
["str":"TestByRefCtor":private]=>
70+
string(12) "aaaaaaaaaaAB"
71+
}
72+
[2]=>
73+
object(TestByRefCtor)#%d (3) {
74+
["id"]=>
75+
string(1) "3"
76+
["val"]=>
77+
string(1) "C"
78+
["str":"TestByRefCtor":private]=>
79+
string(13) "aaaaaaaaaaABC"
80+
}
81+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
--TEST--
2+
PDO Common: PDO::FETCH_CLASS using named arguments in constructor array
3+
--EXTENSIONS--
4+
pdo
5+
--SKIPIF--
6+
<?php
7+
$dir = getenv('REDIR_TEST_DIR');
8+
if (false == $dir) die('skip no driver');
9+
require_once $dir . 'pdo_test.inc';
10+
PDOTest::skip();
11+
?>
12+
--FILE--
13+
<?php
14+
if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/');
15+
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
16+
$db = PDOTest::factory();
17+
18+
$db->exec('CREATE TABLE pdo_fetch_class_ctor_named(id int NOT NULL PRIMARY KEY, val VARCHAR(10), val2 VARCHAR(10))');
19+
$db->exec("INSERT INTO pdo_fetch_class_ctor_named VALUES(1, 'A', 'AA')");
20+
$db->exec("INSERT INTO pdo_fetch_class_ctor_named VALUES(2, 'B', 'BB')");
21+
$db->exec("INSERT INTO pdo_fetch_class_ctor_named VALUES(3, 'C', 'CC')");
22+
23+
$stmt = $db->prepare('SELECT id, val, val2 from pdo_fetch_class_ctor_named');
24+
25+
class TestBase
26+
{
27+
public $id;
28+
protected $val;
29+
private $val2;
30+
31+
public function __construct(string $a, string $b) {
32+
echo 'Value of $a: ', $a, PHP_EOL,
33+
'Value of $b: ', $b, PHP_EOL;
34+
}
35+
}
36+
$stmt->execute();
37+
var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'TestBase', ['b' => 'My key is B', 'a' => 'My key is A']));
38+
39+
?>
40+
--CLEAN--
41+
<?php
42+
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
43+
$db = PDOTest::factory();
44+
PDOTest::dropTableIfExists($db, "pdo_fetch_class_ctor_named");
45+
?>
46+
--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
53+
array(3) {
54+
[0]=>
55+
object(TestBase)#%d (3) {
56+
["id"]=>
57+
string(1) "1"
58+
["val":protected]=>
59+
string(1) "A"
60+
["val2":"TestBase":private]=>
61+
string(2) "AA"
62+
}
63+
[1]=>
64+
object(TestBase)#%d (3) {
65+
["id"]=>
66+
string(1) "2"
67+
["val":protected]=>
68+
string(1) "B"
69+
["val2":"TestBase":private]=>
70+
string(2) "BB"
71+
}
72+
[2]=>
73+
object(TestBase)#%d (3) {
74+
["id"]=>
75+
string(1) "3"
76+
["val":protected]=>
77+
string(1) "C"
78+
["val2":"TestBase":private]=>
79+
string(2) "CC"
80+
}
81+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
--TEST--
2+
PDO Common: PDO::FETCH_CLASS using mixed string and int arguments in constructor array
3+
--EXTENSIONS--
4+
pdo
5+
--SKIPIF--
6+
<?php
7+
$dir = getenv('REDIR_TEST_DIR');
8+
if (false == $dir) die('skip no driver');
9+
require_once $dir . 'pdo_test.inc';
10+
PDOTest::skip();
11+
?>
12+
--FILE--
13+
<?php
14+
if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/');
15+
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
16+
$db = PDOTest::factory();
17+
18+
$db->exec('CREATE TABLE pdo_fetch_class_ctor_named_and_positional(id int NOT NULL PRIMARY KEY, val VARCHAR(10), val2 VARCHAR(10))');
19+
$db->exec("INSERT INTO pdo_fetch_class_ctor_named_and_positional VALUES(1, 'A', 'AA')");
20+
$db->exec("INSERT INTO pdo_fetch_class_ctor_named_and_positional VALUES(2, 'B', 'BB')");
21+
$db->exec("INSERT INTO pdo_fetch_class_ctor_named_and_positional VALUES(3, 'C', 'CC')");
22+
23+
$stmt = $db->prepare('SELECT id, val, val2 from pdo_fetch_class_ctor_named_and_positional');
24+
25+
class TestBase
26+
{
27+
public $id;
28+
protected $val;
29+
private $val2;
30+
31+
public function __construct(string $a, string $b) {
32+
echo 'Value of $a: ', $a, PHP_EOL,
33+
'Value of $b: ', $b, PHP_EOL;
34+
}
35+
}
36+
$stmt->execute();
37+
38+
try {
39+
var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'TestBase', ['b' => 'My key is B', 'No key']));
40+
} catch (\Throwable $e) {
41+
echo $e::class, ': ', $e->getMessage(), \PHP_EOL;
42+
}
43+
44+
?>
45+
--CLEAN--
46+
<?php
47+
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
48+
$db = PDOTest::factory();
49+
PDOTest::dropTableIfExists($db, "pdo_fetch_class_ctor_named_and_positional");
50+
?>
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+
}
+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
--TEST--
2+
PDO Common: PDO::FETCH_CLASS with private constructor and arg by value
3+
--EXTENSIONS--
4+
pdo
5+
--SKIPIF--
6+
<?php
7+
$dir = getenv('REDIR_TEST_DIR');
8+
if (false == $dir) die('skip no driver');
9+
require_once $dir . 'pdo_test.inc';
10+
PDOTest::skip();
11+
?>
12+
--FILE--
13+
<?php
14+
if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/');
15+
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
16+
$db = PDOTest::factory();
17+
18+
$db->exec('CREATE TABLE pdo_fetch_class_private_ctor(id int NOT NULL PRIMARY KEY, val VARCHAR(10), val2 VARCHAR(10))');
19+
$db->exec("INSERT INTO pdo_fetch_class_private_ctor VALUES(1, 'A', 'AA')");
20+
$db->exec("INSERT INTO pdo_fetch_class_private_ctor VALUES(2, 'B', 'BB')");
21+
$stmt = $db->prepare('SELECT id, val FROM pdo_fetch_class_private_ctor');
22+
23+
class TestPrivateCtor
24+
{
25+
public $id;
26+
public $val;
27+
28+
private function __construct(string $str)
29+
{
30+
echo __METHOD__ . "($str, {$this->id})\n";
31+
}
32+
}
33+
34+
class TestDerivedPrivateCtor extends TestPrivateCtor {}
35+
36+
$stmt->execute();
37+
var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'TestPrivateCtor', ['test']));
38+
39+
$stmt->execute();
40+
var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'TestDerivedPrivateCtor', ['testFromDerived']));
41+
42+
?>
43+
--CLEAN--
44+
<?php
45+
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
46+
$db = PDOTest::factory();
47+
PDOTest::dropTableIfExists($db, "pdo_fetch_class_private_ctor");
48+
?>
49+
--EXPECTF--
50+
TestPrivateCtor::__construct(test, 1)
51+
TestPrivateCtor::__construct(test, 2)
52+
array(2) {
53+
[0]=>
54+
object(TestPrivateCtor)#%d (2) {
55+
["id"]=>
56+
string(1) "1"
57+
["val"]=>
58+
string(1) "A"
59+
}
60+
[1]=>
61+
object(TestPrivateCtor)#%d (2) {
62+
["id"]=>
63+
string(1) "2"
64+
["val"]=>
65+
string(1) "B"
66+
}
67+
}
68+
TestPrivateCtor::__construct(testFromDerived, 1)
69+
TestPrivateCtor::__construct(testFromDerived, 2)
70+
array(2) {
71+
[0]=>
72+
object(TestDerivedPrivateCtor)#%d (2) {
73+
["id"]=>
74+
string(1) "1"
75+
["val"]=>
76+
string(1) "A"
77+
}
78+
[1]=>
79+
object(TestDerivedPrivateCtor)#%d (2) {
80+
["id"]=>
81+
string(1) "2"
82+
["val"]=>
83+
string(1) "B"
84+
}
85+
}
File renamed without changes.
File renamed without changes.

Diff for: ext/pdo/tests/pdo_stmt_class_ctor_errors.phpt

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
--TEST--
2+
PDO Common: Setting PDO::FETCH_CLASS with ctor_args when class has no constructor
3+
--EXTENSIONS--
4+
pdo
5+
--SKIPIF--
6+
<?php
7+
$dir = getenv('REDIR_TEST_DIR');
8+
if (false == $dir) die('skip no driver');
9+
require_once $dir . 'pdo_test.inc';
10+
PDOTest::skip();
11+
?>
12+
--FILE--
13+
<?php
14+
if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/');
15+
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
16+
$db = PDOTest::factory();
17+
18+
$db->exec('CREATE TABLE pdo_fetch_all_class_ctor_error(id int NOT NULL PRIMARY KEY, val VARCHAR(10), val2 VARCHAR(10))');
19+
$db->exec("INSERT INTO pdo_fetch_all_class_ctor_error VALUES(1, 'A', 'AA')");
20+
21+
$stmt = $db->prepare('SELECT id, val, val2 from pdo_fetch_all_class_ctor_error');
22+
23+
class TestBase
24+
{
25+
public $id;
26+
protected $val;
27+
private $val2;
28+
}
29+
30+
$stmt->execute();
31+
try {
32+
var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'TestBase', [0]));
33+
} catch (\Throwable $e) {
34+
echo $e::class, ': ', $e->getMessage(), \PHP_EOL;
35+
}
36+
try {
37+
var_dump($stmt->setFetchMode(PDO::FETCH_CLASS, 'TestBase', [0]));
38+
} catch (\Throwable $e) {
39+
echo $e::class, ': ', $e->getMessage(), \PHP_EOL;
40+
}
41+
42+
?>
43+
--CLEAN--
44+
<?php
45+
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
46+
$db = PDOTest::factory();
47+
PDOTest::dropTableIfExists($db, "pdo_fetch_all_class_ctor_error");
48+
?>
49+
--EXPECT--
50+
Error: User-supplied statement does not accept constructor arguments
51+
Error: User-supplied statement does not accept constructor arguments

0 commit comments

Comments
 (0)