Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit fb97b37

Browse files
Add a ReflectionClass::newInstanceFromData() method that behaves the same as PDOStatement::fetchObject()
1 parent 17826d3 commit fb97b37

File tree

5 files changed

+167
-2
lines changed

5 files changed

+167
-2
lines changed

‎ext/reflection/php_reflection.c‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5127,6 +5127,62 @@ ZEND_METHOD(ReflectionClass, newInstanceArgs)
51275127
}
51285128
/* }}} */
51295129

5130+
/* {{{ Returns an instance of this class whose properties are filled with the given data before the constructor is called */
5131+
ZEND_METHOD(ReflectionClass, newInstanceFromData)
5132+
{
5133+
reflection_object *intern;
5134+
zend_class_entry *ce;
5135+
int argc = 0;
5136+
HashTable *data, *args = NULL;
5137+
zend_function *constructor;
5138+
zend_string *key;
5139+
zval *val;
5140+
5141+
GET_REFLECTION_OBJECT_PTR(ce);
5142+
5143+
ZEND_PARSE_PARAMETERS_START(1, 2)
5144+
Z_PARAM_ARRAY_HT(data)
5145+
Z_PARAM_OPTIONAL
5146+
Z_PARAM_ARRAY_HT(args)
5147+
ZEND_PARSE_PARAMETERS_END();
5148+
5149+
if (args) {
5150+
argc = zend_hash_num_elements(args);
5151+
}
5152+
5153+
if (UNEXPECTED(object_init_ex(return_value, ce) != SUCCESS)) {
5154+
return;
5155+
}
5156+
5157+
ZEND_HASH_FOREACH_STR_KEY_VAL(data, key, val) {
5158+
zend_update_property_ex(ce, Z_OBJ_P(return_value), key, val);
5159+
} ZEND_HASH_FOREACH_END();
5160+
5161+
const zend_class_entry *old_scope = EG(fake_scope);
5162+
EG(fake_scope) = ce;
5163+
constructor = Z_OBJ_HT_P(return_value)->get_constructor(Z_OBJ_P(return_value));
5164+
EG(fake_scope) = old_scope;
5165+
5166+
/* Run the constructor if there is one */
5167+
if (constructor) {
5168+
if (!(constructor->common.fn_flags & ZEND_ACC_PUBLIC)) {
5169+
zend_throw_exception_ex(reflection_exception_ptr, 0, "Access to non-public constructor of class %s", ZSTR_VAL(ce->name));
5170+
zval_ptr_dtor(return_value);
5171+
RETURN_NULL();
5172+
}
5173+
5174+
zend_call_known_function(
5175+
constructor, Z_OBJ_P(return_value), Z_OBJCE_P(return_value), NULL, 0, NULL, args);
5176+
5177+
if (EG(exception)) {
5178+
zend_object_store_ctor_failed(Z_OBJ_P(return_value));
5179+
}
5180+
} else if (argc) {
5181+
zend_throw_exception_ex(reflection_exception_ptr, 0, "Class %s does not have a constructor, so you cannot pass any constructor arguments", ZSTR_VAL(ce->name));
5182+
}
5183+
}
5184+
/* }}} */
5185+
51305186
void reflection_class_new_lazy(INTERNAL_FUNCTION_PARAMETERS,
51315187
int strategy, bool is_reset)
51325188
{

‎ext/reflection/php_reflection.stub.php‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,9 @@ public function newInstanceWithoutConstructor(): object {}
370370
/** @tentative-return-type */
371371
public function newInstanceArgs(array $args = []): ?object {}
372372

373+
/** @tentative-return-type */
374+
public function newInstanceFromData(array $data, array $args = []): ?object {}
375+
373376
public function newLazyGhost(callable $initializer, int $options = 0): object {}
374377

375378
public function newLazyProxy(callable $factory, int $options = 0): object {}

‎ext/reflection/php_reflection_arginfo.h‎

Lines changed: 8 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
--TEST--
2+
ReflectionClass::newInstanceFromData
3+
--FILE--
4+
<?php
5+
6+
class A
7+
{
8+
public int $a;
9+
public string $b;
10+
11+
public function __construct($c, $d)
12+
{
13+
echo "In constructor of class A\n";
14+
}
15+
}
16+
17+
class B
18+
{
19+
public int $a;
20+
public string $b;
21+
}
22+
23+
class C
24+
{
25+
}
26+
27+
#[\AllowDynamicProperties]
28+
class D
29+
{
30+
}
31+
32+
33+
$rcA = new ReflectionClass('A');
34+
$rcB = new ReflectionClass('B');
35+
$rcC = new ReflectionClass('C');
36+
$rcD = new ReflectionClass('D');
37+
38+
try
39+
{
40+
$rcA->newInstanceFromData(['a' => 'bad', 'b' => 123], ['foo', 1337]);
41+
}
42+
catch(Throwable $e)
43+
{
44+
echo "Exception: " . $e->getMessage() . "\n";
45+
}
46+
47+
var_dump($rcA->newInstanceFromData(['a' => 123, 'b' => 'good'], ['foo', 1337]));
48+
49+
var_dump($rcB->newInstanceFromData(['a' => 123, 'b' => 'good']));
50+
51+
var_dump($rcC->newInstanceFromData(['a' => 123, 'b' => 'good']));
52+
53+
var_dump($rcC->newInstanceFromData([]));
54+
55+
var_dump($rcD->newInstanceFromData(['a' => 123, 'b' => 'good']));
56+
57+
?>
58+
--EXPECTF--
59+
Exception: Cannot assign string to property A::$a of type int
60+
In constructor of class A
61+
object(A)#5 (2) {
62+
["a"]=>
63+
int(123)
64+
["b"]=>
65+
string(4) "good"
66+
}
67+
object(B)#5 (2) {
68+
["a"]=>
69+
int(123)
70+
["b"]=>
71+
string(4) "good"
72+
}
73+
74+
Deprecated: Creation of dynamic property C::$a is deprecated in %s on line %d
75+
76+
Deprecated: Creation of dynamic property C::$b is deprecated in %s on line %d
77+
object(C)#5 (2) {
78+
["a"]=>
79+
int(123)
80+
["b"]=>
81+
string(4) "good"
82+
}
83+
object(C)#5 (0) {
84+
}
85+
object(D)#5 (2) {
86+
["a"]=>
87+
int(123)
88+
["b"]=>
89+
string(4) "good"
90+
}

‎ext/reflection/tests/ReflectionClass_toString_001.phpt‎

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Class [ <internal:Reflection> class ReflectionClass implements Stringable, Refle
3030
Property [ public string $name ]
3131
}
3232

33-
- Methods [64] {
33+
- Methods [65] {
3434
Method [ <internal:Reflection> private method __clone ] {
3535

3636
- Parameters [0] {
@@ -332,6 +332,15 @@ Class [ <internal:Reflection> class ReflectionClass implements Stringable, Refle
332332
- Tentative return [ ?object ]
333333
}
334334

335+
Method [ <internal:Reflection> public method newInstanceFromData ] {
336+
337+
- Parameters [2] {
338+
Parameter #0 [ <required> array $data ]
339+
Parameter #1 [ <optional> array $args = [] ]
340+
}
341+
- Tentative return [ ?object ]
342+
}
343+
335344
Method [ <internal:Reflection> public method newLazyGhost ] {
336345

337346
- Parameters [2] {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /