Skip to content

ext/pdo: Rename and add tests for PDO::FETCH_CLASS fetch mode #17526

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
81 changes: 81 additions & 0 deletions ext/pdo/tests/pdo_fetch_class_by_ref_constructor.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
--TEST--
PDO Common: PDO::FETCH_CLASS with by-ref constructor and arg by value
--EXTENSIONS--
pdo
--SKIPIF--
<?php
$dir = getenv('REDIR_TEST_DIR');
if (false == $dir) die('skip no driver');
require_once $dir . 'pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/');
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
$db = PDOTest::factory();

$db->exec('CREATE TABLE pdo_fetch_class_by_ref_ctor(id int NOT NULL PRIMARY KEY, val VARCHAR(10), val2 VARCHAR(10))');
$db->exec("INSERT INTO pdo_fetch_class_by_ref_ctor VALUES(1, 'A', 'AA')");
$db->exec("INSERT INTO pdo_fetch_class_by_ref_ctor VALUES(2, 'B', 'BB')");
$db->exec("INSERT INTO pdo_fetch_class_by_ref_ctor VALUES(3, 'C', 'CC')");
$stmt = $db->prepare('SELECT id, val FROM pdo_fetch_class_by_ref_ctor');

class TestByRefCtor
{
public $id;
public $val;
private $str;

public function __construct(string &$str)
{
echo __METHOD__ . "($str, {$this->id})\n";
$str .= $this->val;
$this->str = $str;
}
}

$stmt->execute();
// Use of random_int(10,10) is to defeat SCCP
var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'TestByRefCtor', [str_repeat('a', random_int(10,10))]));

?>
--CLEAN--
<?php
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
$db = PDOTest::factory();
PDOTest::dropTableIfExists($db, "pdo_fetch_class_by_ref_ctor");
?>
--EXPECTF--
TestByRefCtor::__construct(aaaaaaaaaa, 1)
TestByRefCtor::__construct(aaaaaaaaaaA, 2)
TestByRefCtor::__construct(aaaaaaaaaaAB, 3)
array(3) {
[0]=>
object(TestByRefCtor)#%d (3) {
["id"]=>
string(1) "1"
["val"]=>
string(1) "A"
["str":"TestByRefCtor":private]=>
string(11) "aaaaaaaaaaA"
}
[1]=>
object(TestByRefCtor)#%d (3) {
["id"]=>
string(1) "2"
["val"]=>
string(1) "B"
["str":"TestByRefCtor":private]=>
string(12) "aaaaaaaaaaAB"
}
[2]=>
object(TestByRefCtor)#%d (3) {
["id"]=>
string(1) "3"
["val"]=>
string(1) "C"
["str":"TestByRefCtor":private]=>
string(13) "aaaaaaaaaaABC"
}
}
81 changes: 81 additions & 0 deletions ext/pdo/tests/pdo_fetch_class_ctor_with_named_arguments.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
--TEST--
PDO Common: PDO::FETCH_CLASS using named arguments in constructor array
--EXTENSIONS--
pdo
--SKIPIF--
<?php
$dir = getenv('REDIR_TEST_DIR');
if (false == $dir) die('skip no driver');
require_once $dir . 'pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/');
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
$db = PDOTest::factory();

$db->exec('CREATE TABLE pdo_fetch_class_ctor_named(id int NOT NULL PRIMARY KEY, val VARCHAR(10), val2 VARCHAR(10))');
$db->exec("INSERT INTO pdo_fetch_class_ctor_named VALUES(1, 'A', 'AA')");
$db->exec("INSERT INTO pdo_fetch_class_ctor_named VALUES(2, 'B', 'BB')");
$db->exec("INSERT INTO pdo_fetch_class_ctor_named VALUES(3, 'C', 'CC')");

$stmt = $db->prepare('SELECT id, val, val2 from pdo_fetch_class_ctor_named');

class TestBase
{
public $id;
protected $val;
private $val2;

public function __construct(string $a, string $b) {
echo 'Value of $a: ', $a, PHP_EOL,
'Value of $b: ', $b, PHP_EOL;
}
}
$stmt->execute();
var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'TestBase', ['b' => 'My key is B', 'a' => 'My key is A']));

?>
--CLEAN--
<?php
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
$db = PDOTest::factory();
PDOTest::dropTableIfExists($db, "pdo_fetch_class_ctor_named");
?>
--EXPECTF--
Value of $a: My key is B
Value of $b: My key is A
Value of $a: My key is B
Value of $b: My key is A
Value of $a: My key is B
Value of $b: My key is A
array(3) {
[0]=>
object(TestBase)#%d (3) {
["id"]=>
string(1) "1"
["val":protected]=>
string(1) "A"
["val2":"TestBase":private]=>
string(2) "AA"
}
[1]=>
object(TestBase)#%d (3) {
["id"]=>
string(1) "2"
["val":protected]=>
string(1) "B"
["val2":"TestBase":private]=>
string(2) "BB"
}
[2]=>
object(TestBase)#%d (3) {
["id"]=>
string(1) "3"
["val":protected]=>
string(1) "C"
["val2":"TestBase":private]=>
string(2) "CC"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
--TEST--
PDO Common: PDO::FETCH_CLASS using mixed string and int arguments in constructor array
--EXTENSIONS--
pdo
--SKIPIF--
<?php
$dir = getenv('REDIR_TEST_DIR');
if (false == $dir) die('skip no driver');
require_once $dir . 'pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/');
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
$db = PDOTest::factory();

$db->exec('CREATE TABLE pdo_fetch_class_ctor_named_and_positional(id int NOT NULL PRIMARY KEY, val VARCHAR(10), val2 VARCHAR(10))');
$db->exec("INSERT INTO pdo_fetch_class_ctor_named_and_positional VALUES(1, 'A', 'AA')");
$db->exec("INSERT INTO pdo_fetch_class_ctor_named_and_positional VALUES(2, 'B', 'BB')");
$db->exec("INSERT INTO pdo_fetch_class_ctor_named_and_positional VALUES(3, 'C', 'CC')");

$stmt = $db->prepare('SELECT id, val, val2 from pdo_fetch_class_ctor_named_and_positional');

class TestBase
{
public $id;
protected $val;
private $val2;

public function __construct(string $a, string $b) {
echo 'Value of $a: ', $a, PHP_EOL,
'Value of $b: ', $b, PHP_EOL;
}
}
$stmt->execute();

try {
var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'TestBase', ['b' => 'My key is B', 'No key']));
} catch (\Throwable $e) {
echo $e::class, ': ', $e->getMessage(), \PHP_EOL;
}

?>
--CLEAN--
<?php
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
$db = PDOTest::factory();
PDOTest::dropTableIfExists($db, "pdo_fetch_class_ctor_named_and_positional");
?>
--EXPECTF--
Value of $a: My key is B
Value of $b: No key
Value of $a: My key is B
Value of $b: No key
Value of $a: My key is B
Value of $b: No key
array(3) {
[0]=>
object(TestBase)#%d (3) {
["id"]=>
string(1) "1"
["val":protected]=>
string(1) "A"
["val2":"TestBase":private]=>
string(2) "AA"
}
[1]=>
object(TestBase)#%d (3) {
["id"]=>
string(1) "2"
["val":protected]=>
string(1) "B"
["val2":"TestBase":private]=>
string(2) "BB"
}
[2]=>
object(TestBase)#%d (3) {
["id"]=>
string(1) "3"
["val":protected]=>
string(1) "C"
["val2":"TestBase":private]=>
string(2) "CC"
}
}
85 changes: 85 additions & 0 deletions ext/pdo/tests/pdo_fetch_class_private_constructor.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
--TEST--
PDO Common: PDO::FETCH_CLASS with private constructor and arg by value
--EXTENSIONS--
pdo
--SKIPIF--
<?php
$dir = getenv('REDIR_TEST_DIR');
if (false == $dir) die('skip no driver');
require_once $dir . 'pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/');
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
$db = PDOTest::factory();

$db->exec('CREATE TABLE pdo_fetch_class_private_ctor(id int NOT NULL PRIMARY KEY, val VARCHAR(10), val2 VARCHAR(10))');
$db->exec("INSERT INTO pdo_fetch_class_private_ctor VALUES(1, 'A', 'AA')");
$db->exec("INSERT INTO pdo_fetch_class_private_ctor VALUES(2, 'B', 'BB')");
$stmt = $db->prepare('SELECT id, val FROM pdo_fetch_class_private_ctor');

class TestPrivateCtor
{
public $id;
public $val;

private function __construct(string $str)
{
echo __METHOD__ . "($str, {$this->id})\n";
}
}

class TestDerivedPrivateCtor extends TestPrivateCtor {}

$stmt->execute();
var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'TestPrivateCtor', ['test']));

$stmt->execute();
var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'TestDerivedPrivateCtor', ['testFromDerived']));

?>
--CLEAN--
<?php
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
$db = PDOTest::factory();
PDOTest::dropTableIfExists($db, "pdo_fetch_class_private_ctor");
?>
--EXPECTF--
TestPrivateCtor::__construct(test, 1)
TestPrivateCtor::__construct(test, 2)
array(2) {
[0]=>
object(TestPrivateCtor)#%d (2) {
["id"]=>
string(1) "1"
["val"]=>
string(1) "A"
}
[1]=>
object(TestPrivateCtor)#%d (2) {
["id"]=>
string(1) "2"
["val"]=>
string(1) "B"
}
}
TestPrivateCtor::__construct(testFromDerived, 1)
TestPrivateCtor::__construct(testFromDerived, 2)
array(2) {
[0]=>
object(TestDerivedPrivateCtor)#%d (2) {
["id"]=>
string(1) "1"
["val"]=>
string(1) "A"
}
[1]=>
object(TestDerivedPrivateCtor)#%d (2) {
["id"]=>
string(1) "2"
["val"]=>
string(1) "B"
}
}
51 changes: 51 additions & 0 deletions ext/pdo/tests/pdo_stmt_class_ctor_errors.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
--TEST--
PDO Common: Setting PDO::FETCH_CLASS with ctor_args when class has no constructor
--EXTENSIONS--
pdo
--SKIPIF--
<?php
$dir = getenv('REDIR_TEST_DIR');
if (false == $dir) die('skip no driver');
require_once $dir . 'pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/');
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
$db = PDOTest::factory();

$db->exec('CREATE TABLE pdo_fetch_all_class_ctor_error(id int NOT NULL PRIMARY KEY, val VARCHAR(10), val2 VARCHAR(10))');
$db->exec("INSERT INTO pdo_fetch_all_class_ctor_error VALUES(1, 'A', 'AA')");

$stmt = $db->prepare('SELECT id, val, val2 from pdo_fetch_all_class_ctor_error');

class TestBase
{
public $id;
protected $val;
private $val2;
}

$stmt->execute();
try {
var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'TestBase', [0]));
} catch (\Throwable $e) {
echo $e::class, ': ', $e->getMessage(), \PHP_EOL;
}
try {
var_dump($stmt->setFetchMode(PDO::FETCH_CLASS, 'TestBase', [0]));
} catch (\Throwable $e) {
echo $e::class, ': ', $e->getMessage(), \PHP_EOL;
}

?>
--CLEAN--
<?php
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc';
$db = PDOTest::factory();
PDOTest::dropTableIfExists($db, "pdo_fetch_all_class_ctor_error");
?>
--EXPECT--
Error: User-supplied statement does not accept constructor arguments
Error: User-supplied statement does not accept constructor arguments
Loading
Loading