1--TEST--
2PDO::ATTR_STATEMENT_CLASS
3--SKIPIF--
4<?php
5require_once(__DIR__ . DIRECTORY_SEPARATOR . 'skipif.inc');
6require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
7MySQLPDOTest::skip();
8$db = MySQLPDOTest::factory();
9?>
10--FILE--
11<?php
12    require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mysql_pdo_test.inc');
13    $db = MySQLPDOTest::factory();
14    MySQLPDOTest::createTestTable($db);
15
16    $default =  $db->getAttribute(PDO::ATTR_STATEMENT_CLASS);
17    var_dump($default);
18
19    try {
20        $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, 'foo');
21    } catch (\TypeError $e) {
22        echo $e->getMessage(), \PHP_EOL;
23    }
24    try {
25        $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, ['classname']);
26    } catch (\TypeError $e) {
27        echo $e->getMessage(), \PHP_EOL;
28    }
29    // unknown class
30    try {
31        $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, ['classname', []]);
32    } catch (\TypeError $e) {
33        echo $e->getMessage(), \PHP_EOL;
34    }
35
36    // class not derived from PDOStatement
37    class myclass {
38        function __construct() {
39            printf("myclass\n");
40        }
41    }
42
43    try {
44        $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, ['myclass', []]);
45    } catch (\TypeError $e) {
46        echo $e->getMessage(), \PHP_EOL;
47    }
48
49    // public constructor not allowed
50    class mystatement extends PDOStatement {
51        public function __construct() {
52            printf("mystatement\n");
53        }
54    }
55
56    try {
57        if (false !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, ['mystatement', []])))
58            printf("[006] Expecting boolean/false got %s\n", var_export($tmp, true));
59    } catch (\Error $e) {
60        echo get_class($e), ': ', $e->getMessage(), \PHP_EOL;
61    }
62
63
64    // ... but a public destructor is allowed
65    class mystatement2 extends PDOStatement {
66        public function __destruct() {
67            printf("mystatement\n");
68        }
69    }
70
71    if (true !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('mystatement2', array()))))
72        printf("[007] Expecting boolean/true got %s\n", var_export($tmp, true));
73
74    // private constructor
75    class mystatement3 extends PDOStatement {
76        private function __construct($msg) {
77            printf("mystatement3\n");
78            var_dump($msg);
79        }
80    }
81    if (true !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('mystatement3', array('param1')))))
82        printf("[008] Expecting boolean/true got %s\n", var_export($tmp, true));
83
84    // private constructor
85    class mystatement4 extends PDOStatement {
86        private function __construct($msg) {
87            printf("%s\n", get_class($this));
88            var_dump($msg);
89        }
90    }
91    if (true !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('mystatement4', array('param1')))))
92        printf("[008] Expecting boolean/true got %s\n", var_export($tmp, true));
93
94    var_dump($db->getAttribute(PDO::ATTR_STATEMENT_CLASS));
95    $stmt = $db->query('SELECT id, label FROM test ORDER BY id ASC LIMIT 2');
96
97    class mystatement5 extends mystatement4 {
98        public function fetchAll($fetch_style = 1, ...$fetch_args) {
99            return "no data :)";
100        }
101    }
102
103    if (true !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('mystatement5', array('mystatement5')))))
104        printf("[009] Expecting boolean/true got %s\n", var_export($tmp, true));
105    $stmt = $db->query('SELECT id, label FROM test ORDER BY id ASC LIMIT 2');
106    var_dump($stmt->fetchAll());
107
108    if (true !== ($tmp = $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, array('PDOStatement'))))
109        printf("[010] Expecting boolean/true got %s\n", var_export($tmp, true));
110
111    $stmt = $db->query('SELECT id, label FROM test ORDER BY id ASC LIMIT 1');
112    var_dump($stmt->fetchAll());
113
114    // Yes, this is a fatal error and I want it to fail.
115    abstract class mystatement6 extends mystatement5 {
116    }
117    try {
118        $db->setAttribute(PDO::ATTR_STATEMENT_CLASS, ['mystatement6', ['mystatement6']]);
119        $stmt = $db->query('SELECT id, label FROM test ORDER BY id ASC LIMIT 1');
120    } catch (\Error $e) {
121        echo get_class($e), ': ', $e->getMessage(), \PHP_EOL;
122    }
123
124?>
125--EXPECT--
126array(1) {
127  [0]=>
128  string(12) "PDOStatement"
129}
130PDO::ATTR_STATEMENT_CLASS value must be of type array, string given
131PDO::ATTR_STATEMENT_CLASS class must be a valid class
132PDO::ATTR_STATEMENT_CLASS class must be a valid class
133PDO::ATTR_STATEMENT_CLASS class must be derived from PDOStatement
134TypeError: User-supplied statement class cannot have a public constructor
135array(2) {
136  [0]=>
137  string(12) "mystatement4"
138  [1]=>
139  array(1) {
140    [0]=>
141    string(6) "param1"
142  }
143}
144mystatement4
145string(6) "param1"
146mystatement5
147string(12) "mystatement5"
148string(10) "no data :)"
149array(1) {
150  [0]=>
151  array(4) {
152    ["id"]=>
153    string(1) "1"
154    [0]=>
155    string(1) "1"
156    ["label"]=>
157    string(1) "a"
158    [1]=>
159    string(1) "a"
160  }
161}
162Error: Cannot instantiate abstract class mystatement6
163