Coverage Report

Created: 2026-09-14 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/reflection/php_reflection.c
Line
Count
Source
1
/*
2
   +----------------------------------------------------------------------+
3
   | Copyright © The PHP Group and Contributors.                          |
4
   +----------------------------------------------------------------------+
5
   | This source file is subject to the Modified BSD License that is      |
6
   | bundled with this package in the file LICENSE, and is available      |
7
   | through the World Wide Web at <https://www.php.net/license/>.        |
8
   |                                                                      |
9
   | SPDX-License-Identifier: BSD-3-Clause                                |
10
   +----------------------------------------------------------------------+
11
   | Authors: Timm Friebe <thekid@thekid.de>                              |
12
   |          George Schlossnagle <george@omniti.com>                     |
13
   |          Andrei Zmievski <andrei@gravitonic.com>                     |
14
   |          Marcus Boerger <helly@php.net>                              |
15
   |          Johannes Schlueter <johannes@php.net>                       |
16
   +----------------------------------------------------------------------+
17
*/
18
19
#include "zend_compile.h"
20
#include "zend_execute.h"
21
#include "zend_lazy_objects.h"
22
#include "zend_object_handlers.h"
23
#include "zend_type_info.h"
24
#include "zend_types.h"
25
#ifdef HAVE_CONFIG_H
26
#include <config.h>
27
#endif
28
29
#include "php.h"
30
#include "php_ini.h"
31
#include "php_reflection.h"
32
#include "ext/standard/info.h"
33
#include "ext/standard/sha1.h"
34
#include "ext/random/php_random_csprng.h"
35
36
#include "zend.h"
37
#include "zend_API.h"
38
#include "zend_ast.h"
39
#include "zend_attributes.h"
40
#include "zend_exceptions.h"
41
#include "zend_operators.h"
42
#include "zend_constants.h"
43
#include "zend_ini.h"
44
#include "zend_interfaces.h"
45
#include "zend_closures.h"
46
#include "zend_generators.h"
47
#include "zend_extensions.h"
48
#include "zend_builtin_functions.h"
49
#include "zend_smart_str.h"
50
#include "zend_enum.h"
51
#include "zend_fibers.h"
52
53
1.46k
#define REFLECTION_ATTRIBUTE_IS_INSTANCEOF (1 << 1)
54
55
#include "php_reflection_arginfo.h"
56
57
/* Key used to avoid leaking addresses in ReflectionProperty::getId() */
58
0
#define REFLECTION_KEY_LEN 16
59
ZEND_BEGIN_MODULE_GLOBALS(reflection)
60
  bool key_initialized;
61
  unsigned char key[REFLECTION_KEY_LEN];
62
ZEND_END_MODULE_GLOBALS(reflection)
63
ZEND_DECLARE_MODULE_GLOBALS(reflection)
64
65
16
#define REFLECTION_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(reflection, v)
66
67
12.2k
static zend_always_inline zval *reflection_prop_name(zval *object) {
68
  /* $name is always in the first property slot. */
69
12.2k
  ZEND_ASSERT(Z_OBJCE_P(object)->default_properties_count >= 1);
70
12.2k
  return &Z_OBJ_P(object)->properties_table[0];
71
12.2k
}
72
73
2.95k
static zend_always_inline zval *reflection_prop_class(zval *object) {
74
  /* $class is always in the second property slot. */
75
2.95k
  ZEND_ASSERT(Z_OBJCE_P(object)->default_properties_count >= 2);
76
2.95k
  return &Z_OBJ_P(object)->properties_table[1];
77
2.95k
}
78
79
/* Class entry pointers */
80
PHPAPI zend_class_entry *reflector_ptr;
81
PHPAPI zend_class_entry *reflection_exception_ptr;
82
PHPAPI zend_class_entry *reflection_ptr;
83
PHPAPI zend_class_entry *reflection_function_abstract_ptr;
84
PHPAPI zend_class_entry *reflection_function_ptr;
85
PHPAPI zend_class_entry *reflection_generator_ptr;
86
PHPAPI zend_class_entry *reflection_parameter_ptr;
87
PHPAPI zend_class_entry *reflection_type_ptr;
88
PHPAPI zend_class_entry *reflection_named_type_ptr;
89
PHPAPI zend_class_entry *reflection_intersection_type_ptr;
90
PHPAPI zend_class_entry *reflection_union_type_ptr;
91
PHPAPI zend_class_entry *reflection_class_ptr;
92
PHPAPI zend_class_entry *reflection_object_ptr;
93
PHPAPI zend_class_entry *reflection_method_ptr;
94
PHPAPI zend_class_entry *reflection_property_ptr;
95
PHPAPI zend_class_entry *reflection_class_constant_ptr;
96
PHPAPI zend_class_entry *reflection_extension_ptr;
97
PHPAPI zend_class_entry *reflection_zend_extension_ptr;
98
PHPAPI zend_class_entry *reflection_reference_ptr;
99
PHPAPI zend_class_entry *reflection_attribute_ptr;
100
PHPAPI zend_class_entry *reflection_enum_ptr;
101
PHPAPI zend_class_entry *reflection_enum_unit_case_ptr;
102
PHPAPI zend_class_entry *reflection_enum_backed_case_ptr;
103
PHPAPI zend_class_entry *reflection_fiber_ptr;
104
PHPAPI zend_class_entry *reflection_constant_ptr;
105
PHPAPI zend_class_entry *reflection_property_hook_type_ptr;
106
107
15.3k
#define GET_REFLECTION_OBJECT() do { \
108
15.3k
  intern = Z_REFLECTION_P(ZEND_THIS); \
109
15.3k
  if (intern->ptr == NULL) { \
110
0
    if (EG(exception) && EG(exception)->ce == reflection_exception_ptr) { \
111
0
      RETURN_THROWS(); \
112
0
    } \
113
0
    zend_throw_error(NULL, "Internal error: Failed to retrieve the reflection object"); \
114
0
    RETURN_THROWS(); \
115
0
  } \
116
15.3k
} while (0)
117
118
15.1k
#define GET_REFLECTION_OBJECT_PTR(target) do { \
119
15.1k
  GET_REFLECTION_OBJECT(); \
120
15.1k
  target = intern->ptr; \
121
15.1k
} while (0)
122
123
/* {{{ Object structure */
124
125
/* Struct for properties */
126
typedef struct _property_reference {
127
  zend_property_info *prop;
128
  zend_string *unmangled_name;
129
  void *cache_slot[3];
130
} property_reference;
131
132
/* Struct for parameters */
133
typedef struct _parameter_reference {
134
  uint32_t offset;
135
  bool required;
136
  const struct _zend_arg_info *arg_info;
137
  zend_function *fptr;
138
} parameter_reference;
139
140
/* Struct for type hints */
141
typedef struct _type_reference {
142
  zend_type type;
143
  /* Whether to use backwards compatible null representation */
144
  bool legacy_behavior;
145
} type_reference;
146
147
/* Struct for attributes */
148
typedef struct _attribute_reference {
149
  HashTable *attributes;
150
  zend_attribute *data;
151
  zend_class_entry *scope;
152
  zend_string *filename;
153
  uint32_t target;
154
} attribute_reference;
155
156
typedef enum {
157
  REF_TYPE_OTHER,      /* Must be 0 */
158
  REF_TYPE_FUNCTION,
159
  REF_TYPE_GENERATOR,
160
  REF_TYPE_FIBER,
161
  REF_TYPE_PARAMETER,
162
  REF_TYPE_TYPE,
163
  REF_TYPE_PROPERTY,
164
  REF_TYPE_CLASS_CONSTANT,
165
  REF_TYPE_ATTRIBUTE
166
} reflection_type_t;
167
168
/* Struct for reflection objects */
169
typedef struct {
170
  zval obj;
171
  void *ptr;
172
  zend_class_entry *ce;
173
  reflection_type_t ref_type;
174
  zend_object zo;
175
} reflection_object;
176
177
48.6k
#define reflection_object_from_obj(obj) ZEND_CONTAINER_OF(obj, reflection_object, zo)
178
179
27.9k
#define Z_REFLECTION_P(zv) reflection_object_from_obj(Z_OBJ_P((zv)))
180
/* }}} */
181
182
static zend_object_handlers reflection_object_handlers;
183
184
315
static zend_always_inline uint32_t prop_get_flags(const property_reference *ref) {
185
315
  return ref->prop ? ref->prop->flags : ZEND_ACC_PUBLIC;
186
315
}
187
188
325
static inline bool is_closure_invoke(const zend_class_entry *ce, const zend_string *name) {
189
325
  return ce == zend_ce_closure
190
3
    && zend_string_equals_ci(name, ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE));
191
325
}
192
193
static zend_function *_copy_function(zend_function *fptr) /* {{{ */
194
516
{
195
516
  if (fptr
196
516
    && (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
197
44
  {
198
44
    zend_function *copy_fptr = emalloc(sizeof(zend_function));
199
44
    memcpy(copy_fptr, fptr, sizeof(zend_function));
200
44
    copy_fptr->common.function_name = zend_string_copy(fptr->common.function_name);
201
44
    return copy_fptr;
202
44
  }
203
  /* no copy needed */
204
472
  return fptr;
205
516
}
206
/* }}} */
207
208
static void _free_function(zend_function *fptr) /* {{{ */
209
4.98k
{
210
4.98k
  if (fptr
211
3.46k
    && (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
212
81
  {
213
81
    zend_string_release_ex(fptr->common.function_name, false);
214
81
    zend_free_trampoline(fptr);
215
81
  }
216
4.98k
}
217
/* }}} */
218
219
static void reflection_free_property_reference(property_reference *reference)
220
2.15k
{
221
2.15k
  zend_string_release_ex(reference->unmangled_name, false);
222
2.15k
  efree(reference);
223
2.15k
}
224
225
static void reflection_free_parameter_reference(parameter_reference *reference)
226
461
{
227
461
  _free_function(reference->fptr);
228
461
  efree(reference);
229
461
}
230
231
static void reflection_free_objects_storage(zend_object *object) /* {{{ */
232
12.6k
{
233
12.6k
  reflection_object *intern = reflection_object_from_obj(object);
234
235
12.6k
  if (intern->ptr) {
236
12.3k
    switch (intern->ref_type) {
237
456
      case REF_TYPE_PARAMETER:
238
456
        reflection_free_parameter_reference(intern->ptr);
239
456
        break;
240
149
      case REF_TYPE_TYPE: {
241
149
        type_reference *type_ref = intern->ptr;
242
149
        if (ZEND_TYPE_HAS_NAME(type_ref->type)) {
243
39
          zend_string_release(ZEND_TYPE_NAME(type_ref->type));
244
39
        }
245
149
        efree(type_ref);
246
149
        break;
247
0
      }
248
3.00k
      case REF_TYPE_FUNCTION:
249
3.00k
        _free_function(intern->ptr);
250
3.00k
        break;
251
2.15k
      case REF_TYPE_PROPERTY:
252
2.15k
        reflection_free_property_reference(intern->ptr);
253
2.15k
        break;
254
1.68k
      case REF_TYPE_ATTRIBUTE: {
255
1.68k
        attribute_reference *attr_ref = intern->ptr;
256
1.68k
        if (attr_ref->filename) {
257
1.66k
          zend_string_release(attr_ref->filename);
258
1.66k
        }
259
1.68k
        efree(intern->ptr);
260
1.68k
        break;
261
0
      }
262
0
      case REF_TYPE_GENERATOR:
263
0
      case REF_TYPE_FIBER:
264
182
      case REF_TYPE_CLASS_CONSTANT:
265
4.93k
      case REF_TYPE_OTHER:
266
4.93k
        break;
267
12.3k
    }
268
12.3k
  }
269
12.6k
  intern->ptr = NULL;
270
12.6k
  zval_ptr_dtor(&intern->obj);
271
12.6k
  zend_object_std_dtor(object);
272
12.6k
}
273
/* }}} */
274
275
static HashTable *reflection_get_gc(zend_object *obj, zval **gc_data, int *gc_data_count) /* {{{ */
276
8.04k
{
277
8.04k
  reflection_object *intern = reflection_object_from_obj(obj);
278
8.04k
  *gc_data = &intern->obj;
279
8.04k
  *gc_data_count = 1;
280
8.04k
  return zend_std_get_properties(obj);
281
8.04k
}
282
/* }}} */
283
284
static zend_object *reflection_objects_new(zend_class_entry *class_type) /* {{{ */
285
12.6k
{
286
12.6k
  reflection_object *intern = zend_object_alloc(sizeof(reflection_object), class_type);
287
288
12.6k
  zend_object_std_init(&intern->zo, class_type);
289
12.6k
  object_properties_init(&intern->zo, class_type);
290
12.6k
  return &intern->zo;
291
12.6k
}
292
/* }}} */
293
294
static void _const_string(smart_str *str, const zend_string *name, const zval *value, const char *indent);
295
static void _function_string(smart_str *str, const zend_function *fptr, const zend_class_entry *scope, const char *indent);
296
static void _property_string(smart_str *str, const zend_property_info *prop, const zend_string *prop_name, const char *indent);
297
static void _class_const_string(smart_str *str, const zend_string *name, zend_class_constant *c, const char *indent);
298
static void _enum_case_string(smart_str *str, const zend_string *name, zend_class_constant *c, const char *indent);
299
static void _extension_string(smart_str *str, const zend_module_entry *module);
300
static void _zend_extension_string(smart_str *str, const zend_extension *extension);
301
302
/* {{{ _class_string */
303
static void _class_string(smart_str *str, zend_class_entry *ce, zend_object *obj, const char *indent)
304
616
{
305
  /* TBD: Repair indenting of doc comment (or is this to be done in the parser?) */
306
616
  if (ce->doc_comment) {
307
2
    smart_str_appends(str, indent);
308
2
    smart_str_append(str, ce->doc_comment);
309
2
    smart_str_appendc(str, '\n');
310
2
  }
311
312
616
  if (obj) {
313
27
    smart_str_append_printf(str, "%sObject of class [ ", indent);
314
589
  } else {
315
589
    const char *kind = "Class";
316
589
    if (ce->ce_flags & ZEND_ACC_INTERFACE) {
317
71
      kind = "Interface";
318
518
    } else if (ce->ce_flags & ZEND_ACC_TRAIT) {
319
23
      kind = "Trait";
320
495
    } else if (ce->ce_flags & ZEND_ACC_ENUM) {
321
52
      kind = "Enum";
322
52
    }
323
589
    smart_str_append_printf(str, "%s%s [ ", indent, kind);
324
589
  }
325
616
  smart_str_appends(str, (ce->type == ZEND_USER_CLASS) ? "<user" : "<internal");
326
616
  if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module) {
327
205
    smart_str_append_printf(str, ":%s", ce->info.internal.module->name);
328
205
  }
329
616
  smart_str_appends(str, "> ");
330
616
  if (ce->get_iterator != NULL) {
331
24
    smart_str_appends(str, "<iterateable> ");
332
24
  }
333
616
  if (ce->ce_flags & ZEND_ACC_INTERFACE) {
334
71
    smart_str_appends(str, "interface ");
335
545
  } else if (ce->ce_flags & ZEND_ACC_TRAIT) {
336
23
    smart_str_appends(str, "trait ");
337
522
  } else if (ce->ce_flags & ZEND_ACC_ENUM) {
338
52
    smart_str_appends(str, "enum ");
339
470
  } else {
340
470
    if (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
341
17
      smart_str_appends(str, "abstract ");
342
17
    }
343
470
    if (ce->ce_flags & ZEND_ACC_FINAL) {
344
77
      smart_str_appends(str, "final ");
345
77
    }
346
470
    if (ce->ce_flags & ZEND_ACC_READONLY_CLASS) {
347
13
      smart_str_appends(str, "readonly ");
348
13
    }
349
470
    smart_str_appends(str, "class ");
350
470
  }
351
616
  smart_str_append(str, ce->name);
352
616
  if (ce->parent) {
353
95
    smart_str_append_printf(str, " extends %pS", ce->parent->name);
354
95
  }
355
356
  // Show backing type of enums
357
616
  if ((ce->ce_flags & ZEND_ACC_ENUM) && (ce->enum_backing_type != IS_UNDEF)) {
358
3
    smart_str_appends(str,
359
3
      ce->enum_backing_type == IS_STRING ? ": string" : ": int"
360
3
    );
361
3
  }
362
616
  if (ce->num_interfaces) {
363
173
    ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
364
173
    if (ce->ce_flags & ZEND_ACC_INTERFACE) {
365
12
      smart_str_append_printf(str, " extends %pS", ce->interfaces[0]->name);
366
161
    } else {
367
161
      smart_str_append_printf(str, " implements %pS", ce->interfaces[0]->name);
368
161
    }
369
284
    for (uint32_t i = 1; i < ce->num_interfaces; ++i) {
370
111
      smart_str_append_printf(str, ", %pS", ce->interfaces[i]->name);
371
111
    }
372
173
  }
373
616
  smart_str_appends(str, " ] {\n");
374
375
  /* The information where a class is declared is only available for user classes */
376
616
  if (ce->type == ZEND_USER_CLASS) {
377
411
    smart_str_append_printf(str, "%s  @@ %pS %" PRIu32 "-%" PRIu32 "\n", indent, ce->info.user.filename,
378
411
            ce->info.user.line_start, ce->info.user.line_end);
379
411
  }
380
381
616
  zend_string *sub_indent = strpprintf(0, "%s    ", indent);
382
383
  /* Constants */
384
616
  uint32_t total_count = zend_hash_num_elements(&ce->constants_table);
385
616
  uint32_t constant_count = 0;
386
616
  uint32_t enum_case_count = 0;
387
616
  smart_str constant_str = {0};
388
616
  smart_str enum_case_str = {0};
389
  /* So that we don't need to loop through all of the constants multiple
390
   * times (count the constants vs. enum cases, print the constants, print
391
   * the enum cases) use some temporary helper smart strings. */
392
616
  if (total_count > 0) {
393
466
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(CE_CONSTANTS_TABLE(ce), zend_string *key, zend_class_constant *c) {
394
466
      if (ZEND_CLASS_CONST_FLAGS(c) & ZEND_CLASS_CONST_IS_CASE) {
395
64
        _enum_case_string(&enum_case_str, key, c, ZSTR_VAL(sub_indent));
396
64
        enum_case_count++;
397
124
      } else {
398
124
        _class_const_string(&constant_str, key, c, ZSTR_VAL(sub_indent));
399
124
        constant_count++;
400
124
      }
401
466
      if (UNEXPECTED(EG(exception))) {
402
2
        zend_string_release(sub_indent);
403
2
        smart_str_free(&enum_case_str);
404
2
        smart_str_free(&constant_str);
405
2
        return;
406
2
      }
407
466
    } ZEND_HASH_FOREACH_END();
408
45
  }
409
  // Enum cases go first, but the heading is only shown if there are any
410
614
  if (enum_case_count) {
411
13
    smart_str_appendc(str, '\n');
412
13
    smart_str_append_printf(str, "%s  - Enum cases [%" PRIu32 "] {\n", indent, enum_case_count);
413
13
    smart_str_append_smart_str(str, &enum_case_str);
414
13
    smart_str_append_printf(str, "%s  }\n", indent);
415
13
  }
416
614
  smart_str_appendc(str, '\n');
417
614
  smart_str_append_printf(str, "%s  - Constants [%" PRIu32 "] {\n", indent, constant_count);
418
614
  smart_str_append_smart_str(str, &constant_str);
419
614
  smart_str_append_printf(str, "%s  }\n", indent);
420
421
614
  smart_str_free(&enum_case_str);
422
614
  smart_str_free(&constant_str);
423
424
  /* Static properties */
425
  /* counting static properties */
426
614
  uint32_t count = zend_hash_num_elements(&ce->properties_info);
427
614
  uint32_t count_static_props = 0;
428
614
  uint32_t count_shadow_props = 0;
429
614
  if (count > 0) {
430
2.56k
    ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, zend_property_info *prop) {
431
2.56k
      if ((prop->flags & ZEND_ACC_PRIVATE) && prop->ce != ce) {
432
207
        count_shadow_props++;
433
707
      } else if (prop->flags & ZEND_ACC_STATIC) {
434
8
        count_static_props++;
435
8
      }
436
2.56k
    } ZEND_HASH_FOREACH_END();
437
370
  }
438
439
  /* static properties */
440
614
  smart_str_append_printf(str, "\n%s  - Static properties [%" PRIu32 "] {\n", indent, count_static_props);
441
614
  if (count_static_props > 0) {
442
58
    ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, zend_property_info *prop) {
443
58
      if ((prop->flags & ZEND_ACC_STATIC) && (!(prop->flags & ZEND_ACC_PRIVATE) || prop->ce == ce)) {
444
8
        _property_string(str, prop, NULL, ZSTR_VAL(sub_indent));
445
8
      }
446
58
    } ZEND_HASH_FOREACH_END();
447
7
  }
448
614
  smart_str_append_printf(str, "%s  }\n", indent);
449
450
  /* Static methods */
451
  /* counting static methods */
452
614
  count = zend_hash_num_elements(&ce->function_table);
453
614
  uint32_t count_static_funcs = 0;
454
614
  if (count > 0) {
455
4.06k
    ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, zend_function *mptr) {
456
4.06k
      if ((mptr->common.fn_flags & ZEND_ACC_STATIC)
457
126
        && ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce))
458
125
      {
459
125
        count_static_funcs++;
460
125
      }
461
4.06k
    } ZEND_HASH_FOREACH_END();
462
312
  }
463
464
  /* static methods */
465
614
  smart_str_append_printf(str, "\n%s  - Static methods [%" PRIu32 "] {", indent, count_static_funcs);
466
614
  if (count_static_funcs > 0) {
467
876
    ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, zend_function *mptr) {
468
876
      if ((mptr->common.fn_flags & ZEND_ACC_STATIC)
469
125
        && ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce))
470
125
      {
471
125
        smart_str_appendc(str, '\n');
472
125
        _function_string(str, mptr, ce, ZSTR_VAL(sub_indent));
473
125
      }
474
876
    } ZEND_HASH_FOREACH_END();
475
534
  } else {
476
534
    smart_str_appendc(str, '\n');
477
534
  }
478
614
  smart_str_append_printf(str, "%s  }\n", indent);
479
480
  /* Default/Implicit properties */
481
614
  count = zend_hash_num_elements(&ce->properties_info) - count_static_props - count_shadow_props;
482
614
  smart_str_append_printf(str, "\n%s  - Properties [%" PRIu32 "] {\n", indent, count);
483
614
  if (count > 0) {
484
2.54k
    ZEND_HASH_MAP_FOREACH_PTR(&ce->properties_info, zend_property_info *prop) {
485
2.54k
      if (!(prop->flags & ZEND_ACC_STATIC)
486
902
        && (!(prop->flags & ZEND_ACC_PRIVATE) || prop->ce == ce)
487
2.54k
      ) {
488
699
        _property_string(str, prop, NULL, ZSTR_VAL(sub_indent));
489
699
      }
490
2.54k
    } ZEND_HASH_FOREACH_END();
491
366
  }
492
614
  smart_str_append_printf(str, "%s  }\n", indent);
493
494
614
  if (obj) {
495
27
    HashTable *properties = zend_get_properties_no_lazy_init(obj);
496
27
    smart_str prop_str = {0};
497
498
27
    count = 0;
499
27
    if (properties && zend_hash_num_elements(properties)) {
500
95
      ZEND_HASH_FOREACH_STR_KEY(properties, zend_string *prop_name) {
501
95
        if (prop_name && ZSTR_LEN(prop_name) && ZSTR_VAL(prop_name)[0]) { /* skip all private and protected properties */
502
30
          if (!zend_hash_exists(&ce->properties_info, prop_name)) {
503
6
            count++;
504
6
            _property_string(&prop_str, NULL, prop_name, ZSTR_VAL(sub_indent));
505
6
          }
506
30
        }
507
95
      } ZEND_HASH_FOREACH_END();
508
25
    }
509
510
27
    smart_str_append_printf(str, "\n%s  - Dynamic properties [%d] {\n", indent, count);
511
27
    smart_str_append_smart_str(str, &prop_str);
512
27
    smart_str_append_printf(str, "%s  }\n", indent);
513
27
    smart_str_free(&prop_str);
514
27
  }
515
516
  /* Non static methods */
517
614
  count = zend_hash_num_elements(&ce->function_table) - count_static_funcs;
518
614
  if (count > 0) {
519
253
    smart_str method_str = {0};
520
521
253
    count = 0;
522
3.80k
    ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, zend_function *mptr) {
523
3.80k
      if ((mptr->common.fn_flags & ZEND_ACC_STATIC) == 0
524
1.59k
        && ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) == 0 || mptr->common.scope == ce))
525
1.51k
      {
526
1.51k
        zend_function *closure;
527
        /* see if this is a closure */
528
1.51k
        if (obj && is_closure_invoke(ce, mptr->common.function_name)
529
0
          && (closure = zend_get_closure_invoke_method(obj)) != NULL)
530
0
        {
531
0
          mptr = closure;
532
1.51k
        } else {
533
1.51k
          closure = NULL;
534
1.51k
        }
535
1.51k
        smart_str_appendc(&method_str, '\n');
536
1.51k
        _function_string(&method_str, mptr, ce, ZSTR_VAL(sub_indent));
537
1.51k
        count++;
538
1.51k
        _free_function(closure);
539
1.51k
      }
540
3.80k
    } ZEND_HASH_FOREACH_END();
541
253
    smart_str_append_printf(str, "\n%s  - Methods [%" PRIu32 "] {", indent, count);
542
253
    smart_str_append_smart_str(str, &method_str);
543
253
    if (!count) {
544
2
      smart_str_appendc(str, '\n');
545
2
    }
546
253
    smart_str_free(&method_str);
547
361
  } else {
548
361
    smart_str_append_printf(str, "\n%s  - Methods [0] {\n", indent);
549
361
  }
550
614
  smart_str_append_printf(str, "%s  }\n", indent);
551
552
614
  smart_str_append_printf(str, "%s}\n", indent);
553
614
  zend_string_release_ex(sub_indent, false);
554
614
}
555
/* }}} */
556
557
/* {{{ _const_string */
558
static void _const_string(smart_str *str, const zend_string *name, const zval *value, const char *indent)
559
265
{
560
265
  uint32_t flags = Z_CONSTANT_FLAGS_P(value);
561
562
265
  smart_str_appends(str, indent);
563
265
  smart_str_appends(str, "Constant [ ");
564
565
265
  if (flags & (CONST_PERSISTENT|CONST_NO_FILE_CACHE|CONST_DEPRECATED)) {
566
252
    bool first = true;
567
252
    smart_str_appendc(str, '<');
568
569
252
#define DUMP_CONST_FLAG(flag, output) \
570
756
  do { \
571
756
    if (flags & flag) { \
572
261
      if (!first) smart_str_appends(str, ", "); \
573
261
      smart_str_appends(str, output); \
574
261
      first = false; \
575
261
    } \
576
756
  } while (0)
577
252
    DUMP_CONST_FLAG(CONST_PERSISTENT, "persistent");
578
252
    DUMP_CONST_FLAG(CONST_NO_FILE_CACHE, "no_file_cache");
579
252
    DUMP_CONST_FLAG(CONST_DEPRECATED, "deprecated");
580
252
#undef DUMP_CONST_FLAG
581
582
252
    smart_str_appends(str, "> ");
583
252
  }
584
585
265
  const char *type = zend_zval_type_name(value);
586
265
  smart_str_appends(str, type);
587
265
  smart_str_appendc(str, ' ');
588
265
  smart_str_append(str, name);
589
265
  smart_str_appends(str, " ] { ");
590
591
265
  if (Z_TYPE_P(value) == IS_ARRAY) {
592
0
    smart_str_append(str, ZSTR_KNOWN(ZEND_STR_ARRAY_CAPITALIZED));
593
265
  } else if (Z_TYPE_P(value) == IS_STRING) {
594
73
    smart_str_append(str, Z_STR_P(value));
595
192
  } else if (Z_TYPE_P(value) == IS_DOUBLE) {
596
9
    smart_str_append_double(str, Z_DVAL_P(value), (int) EG(precision), false);
597
183
  } else {
598
183
    zend_string *tmp_value_str;
599
183
    zend_string *value_str = zval_get_tmp_string(value, &tmp_value_str);
600
183
    smart_str_append(str, value_str);
601
183
    zend_tmp_string_release(tmp_value_str);
602
183
  }
603
604
265
  smart_str_appends(str, " }\n");
605
265
}
606
/* }}} */
607
608
/* {{{ _class_const_string */
609
static void _class_const_string(smart_str *str, const zend_string *name, zend_class_constant *c, const char *indent)
610
137
{
611
137
  if (Z_TYPE(c->value) == IS_CONSTANT_AST && zend_update_class_constant(c, name, c->ce) == FAILURE) {
612
3
    return;
613
3
  }
614
615
134
  if (c->doc_comment) {
616
3
    smart_str_appends(str, indent);
617
3
    smart_str_append(str, c->doc_comment);
618
3
    smart_str_appendc(str, '\n');
619
3
  }
620
134
  const char *visibility = zend_visibility_string(ZEND_CLASS_CONST_FLAGS(c));
621
134
  const char *final = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_FINAL ? "final " : "";
622
134
  zend_string *type_str = ZEND_TYPE_IS_SET(c->type) ? zend_type_to_string(c->type) : NULL;
623
134
  const char *type = type_str ? ZSTR_VAL(type_str) : zend_zval_type_name(&c->value);
624
625
134
  smart_str_append_printf(str, "%sConstant [ %s%s %s %pS ] { ",
626
134
    indent, final, visibility, type, name);
627
134
  if (Z_TYPE(c->value) == IS_ARRAY) {
628
2
    smart_str_appends(str, "Array");
629
132
  } else if (Z_TYPE(c->value) == IS_OBJECT) {
630
0
    smart_str_appends(str, "Object");
631
132
  } else if (Z_TYPE(c->value) == IS_DOUBLE) {
632
3
    smart_str_append_double(str, Z_DVAL(c->value), (int) EG(precision), false);
633
129
  } else {
634
129
    zend_string *tmp_value_str;
635
129
    zend_string *value_str = zval_get_tmp_string(&c->value, &tmp_value_str);
636
129
    smart_str_append(str, value_str);
637
129
    zend_tmp_string_release(tmp_value_str);
638
129
  }
639
134
  smart_str_appends(str, " }\n");
640
641
134
  if (type_str) {
642
94
    zend_string_release(type_str);
643
94
  }
644
134
}
645
/* }}} */
646
647
static void _enum_case_string(smart_str *str, const zend_string *name, zend_class_constant *c, const char *indent)
648
64
{
649
64
  if (Z_TYPE(c->value) == IS_CONSTANT_AST && zend_update_class_constant(c, name, c->ce) == FAILURE) {
650
0
    return;
651
0
  }
652
653
64
  if (c->doc_comment) {
654
1
    smart_str_appends(str, indent);
655
1
    smart_str_append(str, c->doc_comment);
656
1
    smart_str_appendc(str, '\n');
657
1
  }
658
64
  smart_str_append_printf(str, "%sCase %pS", indent, name);
659
64
  if (c->ce->enum_backing_type == IS_UNDEF) {
660
    // No value
661
61
    smart_str_appendc(str, '\n');
662
61
  } else {
663
    /* Has a value, which is the enum instance, get the value from that.
664
     * We know it must be either a string or integer so no need
665
     * for the IS_ARRAY or IS_OBJECT handling that _class_const_string()
666
     * requires. */
667
3
    zval *enum_val = zend_enum_fetch_case_value(Z_OBJ(c->value));
668
3
    zend_string *tmp_value_str;
669
3
    zend_string *value_str = zval_get_tmp_string(enum_val, &tmp_value_str);
670
3
    smart_str_appends(str, " = ");
671
3
    smart_str_append(str, value_str);
672
3
    smart_str_appendc(str, '\n');
673
3
    zend_tmp_string_release(tmp_value_str);
674
3
  }
675
64
}
676
677
static zend_op *get_recv_op(const zend_op_array *op_array, uint32_t offset)
678
637
{
679
637
  zend_op *op = op_array->opcodes;
680
637
  const zend_op *end = op + op_array->last;
681
682
637
  ++offset;
683
1.48k
  while (op < end) {
684
1.48k
    if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT
685
1.48k
      || op->opcode == ZEND_RECV_VARIADIC) && op->op1.num == offset)
686
637
    {
687
637
      return op;
688
637
    }
689
846
    ++op;
690
846
  }
691
0
  ZEND_ASSERT(0 && "Failed to find op");
692
0
  return NULL;
693
0
}
694
695
637
static zval *get_default_from_recv(const zend_op_array *op_array, uint32_t offset) {
696
637
  zend_op *recv = get_recv_op(op_array, offset);
697
637
  if (!recv || recv->opcode != ZEND_RECV_INIT) {
698
7
    return NULL;
699
7
  }
700
701
630
  return RT_CONSTANT(recv, recv->op2);
702
637
}
703
704
1.70k
static void format_default_value(smart_str *str, const zval *value) {
705
1.70k
  if (smart_str_append_zval(str, value, SIZE_MAX) == SUCCESS) {
706
    /* Nothing to do. */
707
939
  } else if (Z_TYPE_P(value) == IS_ARRAY) {
708
290
    bool is_list = zend_array_is_list(Z_ARRVAL_P(value));
709
290
    bool first = true;
710
290
    smart_str_appendc(str, '[');
711
1.12k
    ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(value), zend_long num_key, zend_string *str_key, zval *zv) {
712
1.12k
      if (!first) {
713
144
        smart_str_appends(str, ", ");
714
144
      }
715
1.12k
      first = false;
716
717
1.12k
      if (!is_list) {
718
153
        if (str_key) {
719
122
          smart_str_appendc(str, '\'');
720
122
          smart_str_append_escaped(str, ZSTR_VAL(str_key), ZSTR_LEN(str_key));
721
122
          smart_str_appendc(str, '\'');
722
122
        } else {
723
31
          smart_str_append_long(str, num_key);
724
31
        }
725
153
        smart_str_appends(str, " => ");
726
153
      }
727
1.12k
      format_default_value(str, zv);
728
1.12k
    } ZEND_HASH_FOREACH_END();
729
290
    smart_str_appendc(str, ']');
730
473
  } else if (Z_TYPE_P(value) == IS_OBJECT) {
731
    /* This branch is reached if the constant AST was already evaluated and
732
     * resulted in an object; enums are already handled in smart_str_append_zval()
733
     * (GH-15902) */
734
3
    const zend_object *obj = Z_OBJ_P(value);
735
3
    const zend_class_entry *class = obj->ce;
736
3
    ZEND_ASSERT(!(class->ce_flags & ZEND_ACC_ENUM));
737
3
    smart_str_appends(str, "object(");
738
3
    smart_str_append(str, class->name);
739
3
    smart_str_appendc(str, ')');
740
470
  } else {
741
470
    ZEND_ASSERT(Z_TYPE_P(value) == IS_CONSTANT_AST);
742
470
    zend_string *ast_str = zend_ast_export("", Z_ASTVAL_P(value), "");
743
470
    smart_str_append(str, ast_str);
744
470
    zend_string_release(ast_str);
745
470
  }
746
1.70k
}
747
748
/* {{{ _parameter_string */
749
static void _parameter_string(smart_str *str, const zend_function *fptr, const zend_arg_info *arg_info, uint32_t offset, bool required)
750
2.04k
{
751
2.04k
  smart_str_append_printf(str, "Parameter #%" PRIu32 " [ ", offset);
752
2.04k
  if (!required) {
753
1.10k
    smart_str_appends(str, "<optional> ");
754
1.10k
  } else {
755
939
    smart_str_appends(str, "<required> ");
756
939
  }
757
2.04k
  if (ZEND_TYPE_IS_SET(arg_info->type)) {
758
1.55k
    zend_string *type_str = zend_type_to_string(arg_info->type);
759
1.55k
    smart_str_append(str, type_str);
760
1.55k
    smart_str_appendc(str, ' ');
761
1.55k
    zend_string_release(type_str);
762
1.55k
  }
763
2.04k
  if (ZEND_ARG_SEND_MODE(arg_info)) {
764
39
    smart_str_appendc(str, '&');
765
39
  }
766
2.04k
  if (ZEND_ARG_IS_VARIADIC(arg_info)) {
767
90
    smart_str_appends(str, "...");
768
90
  }
769
2.04k
  smart_str_append_printf(str, "$%pS", arg_info->name);
770
771
2.04k
  if (!required && !ZEND_ARG_IS_VARIADIC(arg_info)) {
772
1.01k
    if (fptr->type == ZEND_INTERNAL_FUNCTION) {
773
396
      smart_str_appends(str, " = ");
774
      /* TODO: We don't have a way to fetch the default value for an internal function
775
       * with userland arg info. */
776
396
      if (arg_info->default_value) {
777
384
        smart_str_append(str, arg_info->default_value);
778
384
      } else {
779
12
        smart_str_appends(str, "<default>");
780
12
      }
781
623
    } else {
782
623
      const zval *default_value = get_default_from_recv((const zend_op_array*)fptr, offset);
783
623
      if (default_value) {
784
623
        smart_str_appends(str, " = ");
785
623
        format_default_value(str, default_value);
786
623
      }
787
623
    }
788
1.01k
  }
789
2.04k
  smart_str_appends(str, " ]");
790
2.04k
}
791
/* }}} */
792
793
/* {{{ _function_parameter_string */
794
static void _function_parameter_string(smart_str *str, const zend_function *fptr, const char *indent)
795
2.42k
{
796
2.42k
  const zend_arg_info *arg_info = fptr->common.arg_info;
797
2.42k
  if (!arg_info) {
798
102
    return;
799
102
  }
800
801
2.32k
  uint32_t num_args = fptr->common.num_args;
802
2.32k
  if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
803
89
    num_args++;
804
89
  }
805
2.32k
  uint32_t num_required = fptr->common.required_num_args;
806
807
2.32k
  smart_str_appendc(str, '\n');
808
2.32k
  smart_str_append_printf(str, "%s- Parameters [%" PRIu32 "] {\n", indent, num_args);
809
4.35k
  for (uint32_t i = 0; i < num_args; i++) {
810
2.02k
    smart_str_append_printf(str, "%s  ", indent);
811
2.02k
    _parameter_string(str, fptr, arg_info, i, i < num_required);
812
2.02k
    smart_str_appendc(str, '\n');
813
2.02k
    arg_info++;
814
2.02k
  }
815
2.32k
  smart_str_append_printf(str, "%s}\n", indent);
816
2.32k
}
817
/* }}} */
818
819
/* {{{ _function_closure_string */
820
static void _function_closure_string(smart_str *str, const zend_function *fptr, const char *indent)
821
302
{
822
302
  if (fptr->type != ZEND_USER_FUNCTION || !fptr->op_array.static_variables) {
823
207
    return;
824
207
  }
825
826
95
  const HashTable *static_variables = ZEND_MAP_PTR_GET(fptr->op_array.static_variables_ptr);
827
95
  uint32_t count = zend_hash_num_elements(static_variables);
828
829
95
  if (!count) {
830
0
    return;
831
0
  }
832
833
95
  smart_str_appendc(str, '\n');
834
95
  smart_str_append_printf(str, "%s- Bound Variables [%" PRIu32 "] {\n", indent, count);
835
95
  uint32_t i = 0;
836
430
  ZEND_HASH_MAP_FOREACH_STR_KEY(static_variables, const zend_string *key) {
837
430
    smart_str_append_printf(str, "%s    Variable #%" PRIu32 " [ $%pS ]\n", indent, i++, key);
838
430
  } ZEND_HASH_FOREACH_END();
839
95
  smart_str_append_printf(str, "%s}\n", indent);
840
95
}
841
/* }}} */
842
843
/* {{{ _function_string */
844
static void _function_string(smart_str *str, const zend_function *fptr, const zend_class_entry *scope, const char *indent)
845
2.42k
{
846
  /* TBD: Repair indenting of doc comment (or is this to be done in the parser?)
847
   * What's "wrong" is that any whitespace before the doc comment start is
848
   * swallowed, leading to an unaligned comment.
849
   */
850
2.42k
  if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.doc_comment) {
851
2
    smart_str_appends(str, indent);
852
2
    smart_str_append(str, fptr->op_array.doc_comment);
853
2
    smart_str_appendc(str, '\n');
854
2.42k
  } else if (fptr->type == ZEND_INTERNAL_FUNCTION && fptr->internal_function.doc_comment) {
855
0
    smart_str_appends(str, indent);
856
0
    smart_str_append(str, fptr->internal_function.doc_comment);
857
0
    smart_str_appendc(str, '\n');
858
0
  }
859
860
2.42k
  smart_str_appends(str, indent);
861
2.42k
  smart_str_appends(str, fptr->common.fn_flags & ZEND_ACC_CLOSURE ? "Closure [ " : (fptr->common.scope ? "Method [ " : "Function [ "));
862
2.42k
  smart_str_appends(str, (fptr->type == ZEND_USER_FUNCTION) ? "<user" : "<internal");
863
2.42k
  if (fptr->common.fn_flags & ZEND_ACC_DEPRECATED) {
864
10
    smart_str_appends(str, ", deprecated");
865
10
  }
866
2.42k
  if (fptr->type == ZEND_INTERNAL_FUNCTION && ((const zend_internal_function*)fptr)->module) {
867
1.67k
    smart_str_append_printf(str, ":%s", ((const zend_internal_function*)fptr)->module->name);
868
1.67k
  }
869
870
2.42k
  if (scope && fptr->common.scope) {
871
1.78k
    if (fptr->common.scope != scope) {
872
746
      smart_str_append_printf(str, ", inherits %pS", fptr->common.scope->name);
873
1.03k
    } else if (fptr->common.scope->parent) {
874
66
      zend_function *overwrites = zend_hash_find_ptr_lc(
875
66
        &fptr->common.scope->parent->function_table,
876
66
        fptr->common.function_name
877
66
      );
878
66
      if (overwrites != NULL
879
20
        && fptr->common.scope != overwrites->common.scope
880
20
        && !(overwrites->common.fn_flags & ZEND_ACC_PRIVATE)
881
66
      ) {
882
14
        smart_str_append_printf(str, ", overwrites %pS", overwrites->common.scope->name);
883
14
      }
884
66
    }
885
1.78k
  }
886
2.42k
  if (fptr->common.prototype && fptr->common.prototype->common.scope) {
887
825
    smart_str_append_printf(str, ", prototype %pS", fptr->common.prototype->common.scope->name);
888
825
  }
889
2.42k
  if (fptr->common.fn_flags & ZEND_ACC_CTOR) {
890
224
    smart_str_appends(str, ", ctor");
891
224
  }
892
2.42k
  smart_str_appends(str, "> ");
893
894
2.42k
  if (fptr->common.fn_flags & ZEND_ACC_ABSTRACT) {
895
79
    smart_str_appends(str, "abstract ");
896
79
  }
897
2.42k
  if (fptr->common.fn_flags & ZEND_ACC_FINAL) {
898
561
    smart_str_appends(str, "final ");
899
561
  }
900
2.42k
  if (fptr->common.fn_flags & ZEND_ACC_STATIC) {
901
374
    smart_str_appends(str, "static ");
902
374
  }
903
904
2.42k
  if (fptr->common.scope) {
905
    /* These are mutually exclusive */
906
1.87k
    switch (fptr->common.fn_flags & ZEND_ACC_PPP_MASK) {
907
1.80k
      case ZEND_ACC_PUBLIC:
908
1.80k
        smart_str_appends(str, "public ");
909
1.80k
        break;
910
70
      case ZEND_ACC_PRIVATE:
911
70
        smart_str_appends(str, "private ");
912
70
        break;
913
1
      case ZEND_ACC_PROTECTED:
914
1
        smart_str_appends(str, "protected ");
915
1
        break;
916
0
      default:
917
0
        smart_str_appends(str, "<visibility error> ");
918
0
        break;
919
1.87k
    }
920
1.87k
    smart_str_appends(str, "method ");
921
1.87k
  } else {
922
552
    smart_str_appends(str, "function ");
923
552
  }
924
925
2.42k
  if (fptr->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
926
6
    smart_str_appendc(str, '&');
927
6
  }
928
2.42k
  smart_str_append(str, fptr->common.function_name);
929
2.42k
  smart_str_appends(str, " ] {\n");
930
  /* The information where a function is declared is only available for user classes */
931
2.42k
  if (fptr->type == ZEND_USER_FUNCTION) {
932
642
    smart_str_append_printf(str, "%s  @@ %pS %" PRIu32 " - %" PRIu32 "\n", indent,
933
642
            fptr->op_array.filename,
934
642
            fptr->op_array.line_start,
935
642
            fptr->op_array.line_end);
936
642
  }
937
2.42k
  smart_str param_indent = {0};
938
2.42k
  smart_str_append_printf(&param_indent, "%s  ", indent);
939
2.42k
  smart_str_0(&param_indent);
940
2.42k
  if (fptr->common.fn_flags & ZEND_ACC_CLOSURE) {
941
302
    _function_closure_string(str, fptr, ZSTR_VAL(param_indent.s));
942
302
  }
943
2.42k
  _function_parameter_string(str, fptr, ZSTR_VAL(param_indent.s));
944
2.42k
  smart_str_free(&param_indent);
945
2.42k
  if ((fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
946
1.65k
    smart_str_append_printf(str, "  %s- %s [ ", indent, ZEND_ARG_TYPE_IS_TENTATIVE(&fptr->common.arg_info[-1]) ? "Tentative return" : "Return");
947
1.65k
    if (ZEND_TYPE_IS_SET(fptr->common.arg_info[-1].type)) {
948
1.65k
      zend_string *type_str = zend_type_to_string(fptr->common.arg_info[-1].type);
949
1.65k
      smart_str_append_printf(str, "%pS ", type_str);
950
1.65k
      zend_string_release(type_str);
951
1.65k
    }
952
1.65k
    smart_str_appends(str, "]\n");
953
1.65k
  }
954
2.42k
  smart_str_append_printf(str, "%s}\n", indent);
955
2.42k
}
956
/* }}} */
957
958
777
static zval *property_get_default(const zend_property_info *prop_info) {
959
777
  const zend_class_entry *ce = prop_info->ce;
960
777
  if (prop_info->flags & ZEND_ACC_STATIC) {
961
13
    zval *prop = &ce->default_static_members_table[prop_info->offset];
962
13
    ZVAL_DEINDIRECT(prop);
963
13
    return prop;
964
13
  }
965
764
  if (prop_info->flags & ZEND_ACC_VIRTUAL) {
966
19
    return NULL;
967
19
  }
968
745
  return &ce->default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)];
969
764
}
970
971
/* {{{ _property_string */
972
static void _property_string(smart_str *str, const zend_property_info *prop, const zend_string *prop_name, const char *indent)
973
748
{
974
748
  if (!prop) {
975
    // Dynamic property, known to have no doc comment, flags, etc.
976
7
    ZEND_ASSERT(prop_name && "Properties without info must have a name provided");
977
7
    smart_str_append_printf(str, "%sProperty [ <dynamic> public $", indent);
978
7
    smart_str_append(str, prop_name);
979
7
    smart_str_appends(str, " ]\n");
980
7
    return;
981
7
  }
982
741
  if (prop->doc_comment) {
983
2
    smart_str_appends(str, indent);
984
2
    smart_str_append(str, prop->doc_comment);
985
2
    smart_str_appendc(str, '\n');
986
2
  }
987
741
  smart_str_append_printf(str, "%sProperty [ ", indent);
988
741
  if (prop->flags & ZEND_ACC_ABSTRACT) {
989
2
    smart_str_appends(str, "abstract ");
990
2
  }
991
741
  if (prop->flags & ZEND_ACC_FINAL) {
992
2
    smart_str_appends(str, "final ");
993
2
  }
994
  /* These are mutually exclusive */
995
741
  switch (prop->flags & ZEND_ACC_PPP_MASK) {
996
380
    case ZEND_ACC_PUBLIC:
997
380
      smart_str_appends(str, "public ");
998
380
      break;
999
51
    case ZEND_ACC_PRIVATE:
1000
51
      smart_str_appends(str, "private ");
1001
51
      break;
1002
310
    case ZEND_ACC_PROTECTED:
1003
310
      smart_str_appends(str, "protected ");
1004
310
      break;
1005
741
  }
1006
741
  switch (prop->flags & ZEND_ACC_PPP_SET_MASK) {
1007
0
    case ZEND_ACC_PRIVATE_SET:
1008
0
      smart_str_appends(str, "private(set) ");
1009
0
      break;
1010
79
    case ZEND_ACC_PROTECTED_SET:
1011
79
      smart_str_appends(str, "protected(set) ");
1012
79
      break;
1013
0
    case ZEND_ACC_PUBLIC_SET:
1014
0
      ZEND_UNREACHABLE();
1015
0
      break;
1016
741
  }
1017
741
  if (prop->flags & ZEND_ACC_STATIC) {
1018
9
    smart_str_appends(str, "static ");
1019
9
  }
1020
741
  if (prop->flags & ZEND_ACC_READONLY) {
1021
83
    smart_str_appends(str, "readonly ");
1022
83
  }
1023
741
  if (prop->flags & ZEND_ACC_VIRTUAL) {
1024
9
    smart_str_appends(str, "virtual ");
1025
9
  }
1026
741
  if (ZEND_TYPE_IS_SET(prop->type)) {
1027
403
    zend_string *type_str = zend_type_to_string(prop->type);
1028
403
    smart_str_append(str, type_str);
1029
403
    smart_str_appendc(str, ' ');
1030
403
    zend_string_release(type_str);
1031
403
  }
1032
741
  smart_str_appendc(str, '$');
1033
741
  if (!prop_name) {
1034
707
    const char *class_name;
1035
707
    const char *prop_name_cstr;
1036
707
    zend_unmangle_property_name(prop->name, &class_name, &prop_name_cstr);
1037
707
    smart_str_appends(str, prop_name_cstr);
1038
707
  } else {
1039
34
    smart_str_append(str, prop_name);
1040
34
  }
1041
1042
741
  const zval *default_value = property_get_default(prop);
1043
741
  if (default_value && !Z_ISUNDEF_P(default_value)) {
1044
500
    smart_str_appends(str, " = ");
1045
500
    format_default_value(str, default_value);
1046
500
  }
1047
741
  if (prop->hooks != NULL) {
1048
12
    smart_str_appends(str, " {");
1049
12
    const zend_function *get_hooked = prop->hooks[ZEND_PROPERTY_HOOK_GET];
1050
12
    if (get_hooked != NULL) {
1051
12
      if (get_hooked->common.fn_flags & ZEND_ACC_FINAL) {
1052
0
        smart_str_appends(str, " final get;");
1053
12
      } else {
1054
12
        smart_str_appends(str, " get;");
1055
12
      }
1056
12
    }
1057
12
    const zend_function *set_hooked = prop->hooks[ZEND_PROPERTY_HOOK_SET];
1058
12
    if (set_hooked != NULL) {
1059
10
      if (set_hooked->common.fn_flags & ZEND_ACC_FINAL) {
1060
0
        smart_str_appends(str, " final set;");
1061
10
      } else {
1062
10
        smart_str_appends(str, " set;");
1063
10
      }
1064
10
    }
1065
12
    smart_str_appends(str, " }");
1066
12
  }
1067
1068
741
  smart_str_appends(str, " ]\n");
1069
741
}
1070
/* }}} */
1071
1072
static void _extension_ini_string(const zend_ini_entry *ini_entry, smart_str *str, int number) /* {{{ */
1073
537
{
1074
537
  if (number != ini_entry->module_number) {
1075
243
    return;
1076
243
  }
1077
294
  smart_str_append_printf(str, "    Entry [ %pS <", ini_entry->name);
1078
294
  if (ini_entry->modifiable == ZEND_INI_ALL) {
1079
147
    smart_str_appends(str, "ALL");
1080
147
  } else {
1081
147
    const char *comma = "";
1082
147
    if (ini_entry->modifiable & ZEND_INI_USER) {
1083
0
      smart_str_appends(str, "USER");
1084
0
      comma = ",";
1085
0
    }
1086
147
    if (ini_entry->modifiable & ZEND_INI_PERDIR) {
1087
72
      smart_str_append_printf(str, "%sPERDIR", comma);
1088
72
      comma = ",";
1089
72
    }
1090
147
    if (ini_entry->modifiable & ZEND_INI_SYSTEM) {
1091
144
      smart_str_append_printf(str, "%sSYSTEM", comma);
1092
144
    }
1093
147
  }
1094
1095
294
  smart_str_appends(str, "> ]\n");
1096
294
  if (ini_entry->value) {
1097
231
    smart_str_appends(str, "      Current = '");
1098
231
    smart_str_append(str, ini_entry->value);
1099
231
    smart_str_appends(str, "'\n");
1100
231
  } else {
1101
63
    smart_str_appends(str, "      Current = ''\n");
1102
63
  }
1103
294
  if (ini_entry->modified) {
1104
1
    if (ini_entry->orig_value) {
1105
1
      smart_str_appends(str, "      Default = '");
1106
1
      smart_str_append(str, ini_entry->orig_value);
1107
1
      smart_str_appends(str, "'\n");
1108
1
    } else {
1109
0
      smart_str_appends(str, "      Default = ''\n");
1110
0
    }
1111
1
  }
1112
294
  smart_str_appends(str, "    }\n");
1113
294
}
1114
/* }}} */
1115
1116
static void _extension_class_string(zend_class_entry *ce, zend_string *key, smart_str *str, const char *indent, const zend_module_entry *module, uint32_t *num_classes) /* {{{ */
1117
588
{
1118
588
  if (ce->type == ZEND_INTERNAL_CLASS
1119
588
    && ce->info.internal.module
1120
588
    && !strcasecmp(ce->info.internal.module->name, module->name)
1121
    /* dump class if it is not an alias */
1122
120
    && zend_string_equals_ci(ce->name, key)
1123
588
  ) {
1124
120
    smart_str_appendc(str, '\n');
1125
120
    _class_string(str, ce, NULL, indent);
1126
120
    (*num_classes)++;
1127
120
  }
1128
588
}
1129
/* }}} */
1130
1131
static void _extension_string(smart_str *str, const zend_module_entry *module) /* {{{ */
1132
3
{
1133
3
  smart_str_appends(str, "Extension [ ");
1134
3
  if (module->type == MODULE_PERSISTENT) {
1135
3
    smart_str_appends(str, "<persistent>");
1136
3
  }
1137
3
  if (module->type == MODULE_TEMPORARY) {
1138
0
    smart_str_appends(str, "<temporary>" );
1139
0
  }
1140
3
  smart_str_append_printf(str, " extension #%d %s version %s ] {\n",
1141
3
          module->module_number, module->name,
1142
3
          (module->version == NO_VERSION_YET) ? "<no_version>" : module->version);
1143
1144
3
  if (module->deps) {
1145
0
    const zend_module_dep *dep = module->deps;
1146
1147
0
    smart_str_appends(str, "\n  - Dependencies {\n");
1148
1149
0
    while (dep->name) {
1150
0
      smart_str_append_printf(str, "    Dependency [ %s (", dep->name);
1151
1152
0
      switch(dep->type) {
1153
0
        case MODULE_DEP_REQUIRED:
1154
0
          smart_str_appends(str, "Required");
1155
0
          break;
1156
0
        case MODULE_DEP_CONFLICTS:
1157
0
          smart_str_appends(str, "Conflicts");
1158
0
          break;
1159
0
        case MODULE_DEP_OPTIONAL:
1160
0
          smart_str_appends(str, "Optional");
1161
0
          break;
1162
0
        default:
1163
0
          smart_str_appends(str, "Error"); /* shouldn't happen */
1164
0
          break;
1165
0
      }
1166
1167
0
      if (dep->rel) {
1168
0
        smart_str_append_printf(str, " %s", dep->rel);
1169
0
      }
1170
0
      if (dep->version) {
1171
0
        smart_str_append_printf(str, " %s", dep->version);
1172
0
      }
1173
0
      smart_str_appends(str, ") ]\n");
1174
0
      dep++;
1175
0
    }
1176
0
    smart_str_appends(str, "  }\n");
1177
0
  }
1178
1179
3
  {
1180
3
    smart_str str_ini = {0};
1181
1.08k
    ZEND_HASH_MAP_FOREACH_PTR(EG(ini_directives), zend_ini_entry *ini_entry) {
1182
1.08k
      _extension_ini_string(ini_entry, &str_ini, module->module_number);
1183
1.08k
    } ZEND_HASH_FOREACH_END();
1184
3
    if (smart_str_get_len(&str_ini) > 0) {
1185
3
      smart_str_appends(str, "\n  - INI {\n");
1186
3
      smart_str_append_smart_str(str, &str_ini);
1187
3
      smart_str_appends(str, "  }\n");
1188
3
    }
1189
3
    smart_str_free(&str_ini);
1190
3
  }
1191
1192
3
  {
1193
3
    smart_str str_constants = {0};
1194
3
    uint32_t num_constants = 0;
1195
1196
3.30k
    ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), const zend_constant *constant) {
1197
3.30k
      if (ZEND_CONSTANT_MODULE_NUMBER(constant) == module->module_number) {
1198
252
        _const_string(&str_constants, constant->name, &constant->value, "    ");
1199
252
        num_constants++;
1200
252
      }
1201
3.30k
    } ZEND_HASH_FOREACH_END();
1202
1203
3
    if (num_constants) {
1204
3
      smart_str_append_printf(str, "\n  - Constants [%" PRIu32 "] {\n", num_constants);
1205
3
      smart_str_append_smart_str(str, &str_constants);
1206
3
      smart_str_appends(str, "  }\n");
1207
3
    }
1208
3
    smart_str_free(&str_constants);
1209
3
  }
1210
1211
3
  {
1212
3
    bool first = true;
1213
1214
4.15k
    ZEND_HASH_MAP_FOREACH_PTR(CG(function_table), zend_function *fptr) {
1215
4.15k
      if (fptr->common.type==ZEND_INTERNAL_FUNCTION
1216
2.07k
        && fptr->internal_function.module == module
1217
4.15k
      ) {
1218
183
        if (first) {
1219
3
          smart_str_appends(str, "\n  - Functions {\n");
1220
3
          first = false;
1221
3
        }
1222
183
        _function_string(str, fptr, NULL, "    ");
1223
183
      }
1224
4.15k
    } ZEND_HASH_FOREACH_END();
1225
3
    if (!first) {
1226
3
      smart_str_appends(str, "  }\n");
1227
3
    }
1228
3
  }
1229
1230
3
  {
1231
3
    smart_str str_classes = {0};
1232
3
    uint32_t num_classes = 0;
1233
1234
1.18k
    ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(class_table), zend_string *key, zend_class_entry *ce) {
1235
1.18k
      _extension_class_string(ce, key, &str_classes, "    ", module, &num_classes);
1236
1.18k
    } ZEND_HASH_FOREACH_END();
1237
3
    if (num_classes) {
1238
3
      smart_str_append_printf(str, "\n  - Classes [%" PRIu32 "] {", num_classes);
1239
3
      smart_str_append_smart_str(str, &str_classes);
1240
3
      smart_str_appends(str, "  }\n");
1241
3
    }
1242
3
    smart_str_free(&str_classes);
1243
3
  }
1244
1245
3
  smart_str_appends(str, "}\n");
1246
3
}
1247
/* }}} */
1248
1249
/* {{{ reflection_attribute_factory */
1250
static void reflection_attribute_factory(zval *object, HashTable *attributes, zend_attribute *data,
1251
    zend_class_entry *scope, uint32_t target, zend_string *filename)
1252
1.68k
{
1253
1.68k
  object_init_ex(object, reflection_attribute_ptr);
1254
1.68k
  reflection_object *intern = Z_REFLECTION_P(object);
1255
1.68k
  attribute_reference *reference = (attribute_reference*) emalloc(sizeof(attribute_reference));
1256
1.68k
  reference->attributes = attributes;
1257
1.68k
  reference->data = data;
1258
1.68k
  reference->scope = scope;
1259
1.68k
  reference->filename = filename ? zend_string_copy(filename) : NULL;
1260
1.68k
  reference->target = target;
1261
1.68k
  intern->ptr = reference;
1262
1.68k
  intern->ref_type = REF_TYPE_ATTRIBUTE;
1263
1.68k
  ZVAL_STR_COPY(reflection_prop_name(object), data->name);
1264
1.68k
}
1265
/* }}} */
1266
1267
static zend_result read_attributes(zval *ret, HashTable *attributes, zend_class_entry *scope,
1268
    uint32_t offset, uint32_t target, zend_string *name, const zend_class_entry *base, zend_string *filename) /* {{{ */
1269
1.20k
{
1270
1.20k
  ZEND_ASSERT(attributes != NULL);
1271
1.20k
  zval tmp;
1272
1273
1.20k
  if (name) {
1274
    // Name based filtering using lowercased key.
1275
120
    zend_string *filter = zend_string_tolower(name);
1276
1277
540
    ZEND_HASH_PACKED_FOREACH_PTR(attributes, zend_attribute *attr) {
1278
540
      if (attr->offset == offset && zend_string_equals(attr->lcname, filter)) {
1279
111
        reflection_attribute_factory(&tmp, attributes, attr, scope, target, filename);
1280
111
        add_next_index_zval(ret, &tmp);
1281
111
      }
1282
540
    } ZEND_HASH_FOREACH_END();
1283
1284
120
    zend_string_release(filter);
1285
120
    return SUCCESS;
1286
120
  }
1287
1288
5.80k
  ZEND_HASH_PACKED_FOREACH_PTR(attributes, zend_attribute *attr) {
1289
5.80k
    if (attr->offset != offset) {
1290
227
      continue;
1291
227
    }
1292
1293
1.59k
    if (base) {
1294
      // Base type filtering.
1295
65
      const zend_class_entry *ce = zend_lookup_class_ex(attr->name, attr->lcname, 0);
1296
1297
65
      if (ce == NULL) {
1298
        // Bailout on error, otherwise ignore unavailable class.
1299
5
        if (EG(exception)) {
1300
0
          return FAILURE;
1301
0
        }
1302
1303
5
        continue;
1304
5
      }
1305
1306
60
      if (!instanceof_function(ce, base)) {
1307
20
        continue;
1308
20
      }
1309
60
    }
1310
1311
1.57k
    reflection_attribute_factory(&tmp, attributes, attr, scope, target, filename);
1312
1.57k
    add_next_index_zval(ret, &tmp);
1313
1.57k
  } ZEND_HASH_FOREACH_END();
1314
1315
1.08k
  return SUCCESS;
1316
1.08k
}
1317
/* }}} */
1318
1319
static void reflect_attributes(INTERNAL_FUNCTION_PARAMETERS, HashTable *attributes,
1320
    uint32_t offset, zend_class_entry *scope, uint32_t target, zend_string *filename) /* {{{ */
1321
1.31k
{
1322
1.31k
  zend_string *name = NULL;
1323
1.31k
  zend_long flags = 0;
1324
1.31k
  const zend_class_entry *base = NULL;
1325
1326
1.31k
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!l", &name, &flags) == FAILURE) {
1327
0
    RETURN_THROWS();
1328
0
  }
1329
1330
1.31k
  if (flags & ~REFLECTION_ATTRIBUTE_IS_INSTANCEOF) {
1331
5
    zend_argument_value_error(2, "must be a valid attribute filter flag");
1332
5
    RETURN_THROWS();
1333
5
  }
1334
1335
1.30k
  if (name && (flags & REFLECTION_ATTRIBUTE_IS_INSTANCEOF)) {
1336
33
    if (NULL == (base = zend_lookup_class(name))) {
1337
8
      if (!EG(exception)) {
1338
8
        zend_throw_error(NULL, "Class \"%pS\" not found", name);
1339
8
      }
1340
1341
8
      RETURN_THROWS();
1342
8
    }
1343
1344
25
    name = NULL;
1345
25
  }
1346
1347
1.29k
  if (!attributes) {
1348
98
    RETURN_EMPTY_ARRAY();
1349
98
  }
1350
1351
1.20k
  array_init(return_value);
1352
1353
1.20k
  if (FAILURE == read_attributes(return_value, attributes, scope, offset, target, name, base, filename)) {
1354
0
    RETURN_THROWS();
1355
0
  }
1356
1.20k
}
1357
/* }}} */
1358
1359
static void _zend_extension_string(smart_str *str, const zend_extension *extension) /* {{{ */
1360
0
{
1361
0
  smart_str_append_printf(str, "Zend Extension [ %s ", extension->name);
1362
1363
0
  if (extension->version) {
1364
0
    smart_str_append_printf(str, "%s ", extension->version);
1365
0
  }
1366
0
  if (extension->copyright) {
1367
0
    smart_str_append_printf(str, "%s ", extension->copyright);
1368
0
  }
1369
0
  if (extension->author) {
1370
0
    smart_str_append_printf(str, "by %s ", extension->author);
1371
0
  }
1372
0
  if (extension->URL) {
1373
0
    smart_str_append_printf(str, "<%s> ", extension->URL);
1374
0
  }
1375
1376
0
  smart_str_appends(str, "]\n");
1377
0
}
1378
/* }}} */
1379
1380
/* {{{ _function_check_flag */
1381
static void _function_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask)
1382
231
{
1383
231
  const reflection_object *intern;
1384
231
  const zend_function *mptr;
1385
1386
231
  ZEND_PARSE_PARAMETERS_NONE();
1387
231
  GET_REFLECTION_OBJECT_PTR(mptr);
1388
231
  RETURN_BOOL(mptr->common.fn_flags & mask);
1389
231
}
1390
/* }}} */
1391
1392
/* {{{ zend_reflection_class_factory */
1393
PHPAPI void zend_reflection_class_factory(zend_class_entry *ce, zval *object)
1394
214
{
1395
214
  zend_class_entry *reflection_ce =
1396
214
    ce->ce_flags & ZEND_ACC_ENUM ? reflection_enum_ptr : reflection_class_ptr;
1397
214
  object_init_ex(object, reflection_ce);
1398
214
  reflection_object *intern = Z_REFLECTION_P(object);
1399
214
  intern->ptr = ce;
1400
214
  intern->ref_type = REF_TYPE_OTHER;
1401
214
  intern->ce = ce;
1402
214
  ZVAL_STR_COPY(reflection_prop_name(object), ce->name);
1403
214
}
1404
/* }}} */
1405
1406
/* {{{ reflection_extension_factory */
1407
static void reflection_extension_factory(zval *object, zend_module_entry *module)
1408
3
{
1409
3
  object_init_ex(object, reflection_extension_ptr);
1410
3
  reflection_object *intern = Z_REFLECTION_P(object);
1411
3
  intern->ptr = module;
1412
3
  intern->ref_type = REF_TYPE_OTHER;
1413
3
  intern->ce = NULL;
1414
3
  ZVAL_STRING(reflection_prop_name(object), module->name);
1415
3
}
1416
/* }}} */
1417
1418
/* {{{ reflection_parameter_factory */
1419
static void reflection_parameter_factory(zend_function *fptr, zval *closure_object, const zend_arg_info *arg_info, uint32_t offset, bool required, zval *object)
1420
419
{
1421
419
  object_init_ex(object, reflection_parameter_ptr);
1422
419
  reflection_object *intern = Z_REFLECTION_P(object);
1423
419
  parameter_reference *reference = (parameter_reference*) emalloc(sizeof(parameter_reference));
1424
419
  reference->arg_info = arg_info;
1425
419
  reference->offset = offset;
1426
419
  reference->required = required;
1427
419
  reference->fptr = fptr;
1428
419
  intern->ptr = reference;
1429
419
  intern->ref_type = REF_TYPE_PARAMETER;
1430
419
  intern->ce = fptr->common.scope;
1431
419
  if (closure_object) {
1432
286
    ZVAL_OBJ_COPY(&intern->obj, Z_OBJ_P(closure_object));
1433
286
  }
1434
1435
419
  zval *prop_name = reflection_prop_name(object);
1436
419
  ZVAL_STR_COPY(prop_name, arg_info->name);
1437
419
}
1438
/* }}} */
1439
1440
typedef enum {
1441
  NAMED_TYPE = 0,
1442
  UNION_TYPE = 1,
1443
  INTERSECTION_TYPE = 2
1444
} reflection_type_kind;
1445
1446
/* For backwards compatibility reasons, we need to return T|null style unions
1447
 * and transformation from iterable to Traversable|array
1448
 * as a ReflectionNamedType. Here we determine what counts as a union type and
1449
 * what doesn't. */
1450
149
static reflection_type_kind get_type_kind(zend_type type) {
1451
149
  uint32_t type_mask_without_null = ZEND_TYPE_PURE_MASK_WITHOUT_NULL(type);
1452
1453
149
  if (ZEND_TYPE_HAS_LIST(type)) {
1454
0
    if (ZEND_TYPE_IS_INTERSECTION(type)) {
1455
0
      return INTERSECTION_TYPE;
1456
0
    }
1457
0
    ZEND_ASSERT(ZEND_TYPE_IS_UNION(type));
1458
0
    return UNION_TYPE;
1459
0
  }
1460
1461
149
  if (ZEND_TYPE_IS_COMPLEX(type)) {
1462
    /* BC support for 'iterable' type */
1463
39
    if (UNEXPECTED(ZEND_TYPE_IS_ITERABLE_FALLBACK(type))) {
1464
0
      return NAMED_TYPE;
1465
0
    }
1466
39
    if (type_mask_without_null != 0) {
1467
0
      return UNION_TYPE;
1468
0
    }
1469
39
    return NAMED_TYPE;
1470
39
  }
1471
110
  if (type_mask_without_null == MAY_BE_BOOL || ZEND_TYPE_PURE_MASK(type) == MAY_BE_ANY) {
1472
5
    return NAMED_TYPE;
1473
5
  }
1474
  /* Check that only one bit is set. */
1475
105
  if ((type_mask_without_null & (type_mask_without_null - 1)) != 0) {
1476
0
    return UNION_TYPE;
1477
0
  }
1478
105
  return NAMED_TYPE;
1479
105
}
1480
1481
/* {{{ reflection_type_factory */
1482
static void reflection_type_factory(zend_type type, zval *object, bool legacy_behavior)
1483
149
{
1484
149
  reflection_type_kind type_kind = get_type_kind(type);
1485
149
  bool is_mixed = ZEND_TYPE_PURE_MASK(type) == MAY_BE_ANY;
1486
149
  bool is_only_null = (ZEND_TYPE_PURE_MASK(type) == MAY_BE_NULL && !ZEND_TYPE_IS_COMPLEX(type));
1487
1488
149
  switch (type_kind) {
1489
0
    case INTERSECTION_TYPE:
1490
0
      object_init_ex(object, reflection_intersection_type_ptr);
1491
0
      break;
1492
0
    case UNION_TYPE:
1493
0
      object_init_ex(object, reflection_union_type_ptr);
1494
0
      break;
1495
149
    case NAMED_TYPE:
1496
149
      object_init_ex(object, reflection_named_type_ptr);
1497
149
      break;
1498
0
    default: ZEND_UNREACHABLE();
1499
149
  }
1500
1501
149
  reflection_object *intern = Z_REFLECTION_P(object);
1502
149
  type_reference *reference = (type_reference*) emalloc(sizeof(type_reference));
1503
149
  reference->type = type;
1504
149
  reference->legacy_behavior = legacy_behavior && type_kind == NAMED_TYPE && !is_mixed && !is_only_null;
1505
149
  intern->ptr = reference;
1506
149
  intern->ref_type = REF_TYPE_TYPE;
1507
1508
  /* Property types may be resolved during the lifetime of the ReflectionType.
1509
   * If we reference a string, make sure it doesn't get released. However, only
1510
   * do this for the top-level type, as resolutions inside type lists will be
1511
   * fully visible to us (we'd have to do a fully copy of the type if we wanted
1512
   * to prevent that). */
1513
149
  if (ZEND_TYPE_HAS_NAME(type)) {
1514
39
    zend_string_addref(ZEND_TYPE_NAME(type));
1515
39
  }
1516
149
}
1517
/* }}} */
1518
1519
/* {{{ reflection_function_factory */
1520
static void reflection_function_factory(zend_function *function, zval *closure_object, zval *object)
1521
1.03k
{
1522
1.03k
  object_init_ex(object, reflection_function_ptr);
1523
1.03k
  reflection_object *intern = Z_REFLECTION_P(object);
1524
1.03k
  intern->ptr = function;
1525
1.03k
  intern->ref_type = REF_TYPE_FUNCTION;
1526
1.03k
  intern->ce = NULL;
1527
1.03k
  if (closure_object) {
1528
0
    ZVAL_OBJ_COPY(&intern->obj, Z_OBJ_P(closure_object));
1529
0
  }
1530
1.03k
  ZVAL_STR_COPY(reflection_prop_name(object), function->common.function_name);
1531
1.03k
}
1532
/* }}} */
1533
1534
/* {{{ reflection_method_factory */
1535
static void reflection_method_factory(zend_class_entry *ce, zend_function *method, zval *closure_object, zval *object)
1536
393
{
1537
393
  object_init_ex(object, reflection_method_ptr);
1538
393
  reflection_object *intern = Z_REFLECTION_P(object);
1539
393
  intern->ptr = method;
1540
393
  intern->ref_type = REF_TYPE_FUNCTION;
1541
393
  intern->ce = ce;
1542
393
  if (closure_object) {
1543
1
    ZVAL_OBJ_COPY(&intern->obj, Z_OBJ_P(closure_object));
1544
1
  }
1545
1546
393
  ZVAL_STR_COPY(reflection_prop_name(object), method->common.function_name);
1547
393
  ZVAL_STR_COPY(reflection_prop_class(object), method->common.scope->name);
1548
393
}
1549
/* }}} */
1550
1551
/* {{{ reflection_property_factory */
1552
static void reflection_property_factory(zend_class_entry *ce, zend_string *name, zend_property_info *prop, zval *object)
1553
1.50k
{
1554
1.50k
  object_init_ex(object, reflection_property_ptr);
1555
1.50k
  reflection_object *intern = Z_REFLECTION_P(object);
1556
1.50k
  property_reference *reference = (property_reference*) emalloc(sizeof(property_reference));
1557
1.50k
  reference->prop = prop;
1558
1.50k
  reference->unmangled_name = zend_string_copy(name);
1559
1.50k
  memset(reference->cache_slot, 0, sizeof(reference->cache_slot));
1560
1.50k
  intern->ptr = reference;
1561
1.50k
  intern->ref_type = REF_TYPE_PROPERTY;
1562
1.50k
  intern->ce = ce;
1563
1.50k
  ZVAL_STR_COPY(reflection_prop_name(object), name);
1564
1.50k
  ZVAL_STR_COPY(reflection_prop_class(object), prop ? prop->ce->name : ce->name);
1565
1.50k
}
1566
/* }}} */
1567
1568
static void reflection_property_factory_str(zend_class_entry *ce, const char *name_str, size_t name_len, zend_property_info *prop, zval *object)
1569
1
{
1570
1
  zend_string *name = zend_string_init(name_str, name_len, false);
1571
1
  reflection_property_factory(ce, name, prop, object);
1572
1
  zend_string_release_ex(name, false);
1573
1
}
1574
1575
/* {{{ reflection_class_constant_factory */
1576
static void reflection_class_constant_factory(zend_string *name_str, zend_class_constant *constant, zval *object)
1577
83
{
1578
83
  object_init_ex(object, reflection_class_constant_ptr);
1579
83
  reflection_object *intern = Z_REFLECTION_P(object);
1580
83
  intern->ptr = constant;
1581
83
  intern->ref_type = REF_TYPE_CLASS_CONSTANT;
1582
83
  intern->ce = constant->ce;
1583
1584
83
  ZVAL_STR_COPY(reflection_prop_name(object), name_str);
1585
83
  ZVAL_STR_COPY(reflection_prop_class(object), constant->ce->name);
1586
83
}
1587
/* }}} */
1588
1589
static void reflection_enum_case_factory(const zend_class_entry *ce, zend_string *name_str, zend_class_constant *constant, zval *object)
1590
4
{
1591
4
  zend_class_entry *case_reflection_class = ce->enum_backing_type == IS_UNDEF
1592
4
    ? reflection_enum_unit_case_ptr
1593
4
    : reflection_enum_backed_case_ptr;
1594
4
  object_init_ex(object, case_reflection_class);
1595
4
  reflection_object *intern = Z_REFLECTION_P(object);
1596
4
  intern->ptr = constant;
1597
4
  intern->ref_type = REF_TYPE_CLASS_CONSTANT;
1598
4
  intern->ce = constant->ce;
1599
1600
4
  ZVAL_STR_COPY(reflection_prop_name(object), name_str);
1601
4
  ZVAL_STR_COPY(reflection_prop_class(object), constant->ce->name);
1602
4
}
1603
1604
5
static zend_result get_parameter_default(zval *result, const parameter_reference *param) {
1605
5
  if (param->fptr->type == ZEND_INTERNAL_FUNCTION) {
1606
1
    if (param->fptr->common.fn_flags & ZEND_ACC_USER_ARG_INFO) {
1607
      /* We don't have a way to determine the default value for this case right now. */
1608
1
      return FAILURE;
1609
1
    }
1610
0
    return zend_get_default_from_internal_arg_info(result, param->arg_info);
1611
1
  }
1612
4
  zval *default_value = get_default_from_recv((const zend_op_array *) param->fptr, param->offset);
1613
4
  if (!default_value) {
1614
0
    return FAILURE;
1615
0
  }
1616
1617
4
  ZVAL_COPY(result, default_value);
1618
4
  return SUCCESS;
1619
4
}
1620
1621
/* {{{ Preventing __clone from being called */
1622
ZEND_METHOD(ReflectionClass, __clone)
1623
0
{
1624
  /* __clone() is private but this is reachable with reflection */
1625
0
  zend_throw_exception(reflection_exception_ptr, "Cannot clone object using __clone()", 0);
1626
0
}
1627
/* }}} */
1628
1629
/* {{{ Returns an array of modifier names */
1630
ZEND_METHOD(Reflection, getModifierNames)
1631
2
{
1632
2
  zend_long modifiers;
1633
1634
2
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &modifiers) == FAILURE) {
1635
0
    RETURN_THROWS();
1636
0
  }
1637
1638
2
  array_init(return_value);
1639
1640
2
  if (modifiers & (ZEND_ACC_ABSTRACT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
1641
0
    add_next_index_stringl(return_value, "abstract", sizeof("abstract")-1);
1642
0
  }
1643
2
  if (modifiers & ZEND_ACC_FINAL) {
1644
1
    add_next_index_stringl(return_value, "final", sizeof("final")-1);
1645
1
  }
1646
2
  if (modifiers & ZEND_ACC_VIRTUAL) {
1647
0
    add_next_index_stringl(return_value, "virtual", sizeof("virtual")-1);
1648
0
  }
1649
1650
  /* These are mutually exclusive */
1651
2
  switch (modifiers & ZEND_ACC_PPP_MASK) {
1652
0
    case ZEND_ACC_PUBLIC:
1653
0
      add_next_index_stringl(return_value, "public", sizeof("public")-1);
1654
0
      break;
1655
0
    case ZEND_ACC_PRIVATE:
1656
0
      add_next_index_stringl(return_value, "private", sizeof("private")-1);
1657
0
      break;
1658
1
    case ZEND_ACC_PROTECTED:
1659
1
      add_next_index_stringl(return_value, "protected", sizeof("protected")-1);
1660
1
      break;
1661
2
  }
1662
  /* These are also mutually exclusive */
1663
2
  switch (modifiers & ZEND_ACC_PPP_SET_MASK) {
1664
0
    case ZEND_ACC_PROTECTED_SET:
1665
0
      add_next_index_stringl(return_value, "protected(set)", sizeof("protected(set)")-1);
1666
0
      break;
1667
0
    case ZEND_ACC_PRIVATE_SET:
1668
0
      add_next_index_stringl(return_value, "private(set)", sizeof("private(set)")-1);
1669
0
      break;
1670
2
  }
1671
1672
2
  if (modifiers & ZEND_ACC_STATIC) {
1673
0
    add_next_index_str(return_value, ZSTR_KNOWN(ZEND_STR_STATIC));
1674
0
  }
1675
1676
2
  if (modifiers & (ZEND_ACC_READONLY | ZEND_ACC_READONLY_CLASS)) {
1677
0
    add_next_index_stringl(return_value, "readonly", sizeof("readonly")-1);
1678
0
  }
1679
2
}
1680
/* }}} */
1681
1682
/* {{{ Constructor. Throws an Exception in case the given function does not exist */
1683
ZEND_METHOD(ReflectionFunction, __construct)
1684
1.37k
{
1685
1.37k
  zend_object *closure_obj = NULL;
1686
1.37k
  zend_function *fptr;
1687
1.37k
  zend_string *fname;
1688
1689
1.37k
  zval *object = ZEND_THIS;
1690
1.37k
  reflection_object *intern = Z_REFLECTION_P(object);
1691
1692
4.10k
  ZEND_PARSE_PARAMETERS_START(1, 1)
1693
6.82k
    Z_PARAM_OBJ_OF_CLASS_OR_STR(closure_obj, zend_ce_closure, fname)
1694
6.82k
  ZEND_PARSE_PARAMETERS_END();
1695
1696
1.36k
  if (closure_obj) {
1697
931
    fptr = (zend_function*)zend_get_closure_method_def(closure_obj);
1698
931
  } else {
1699
433
    fptr = zend_fetch_function(fname);
1700
1701
433
    if (fptr == NULL) {
1702
14
      zend_throw_exception_ex(reflection_exception_ptr, 0,
1703
14
        "Function %pS() does not exist", fname);
1704
14
      RETURN_THROWS();
1705
14
    }
1706
433
  }
1707
1708
1.35k
  if (intern->ptr) {
1709
0
    zval_ptr_dtor(&intern->obj);
1710
0
    zval_ptr_dtor(reflection_prop_name(object));
1711
0
  }
1712
1713
1.35k
  ZVAL_STR_COPY(reflection_prop_name(object), fptr->common.function_name);
1714
1.35k
  intern->ptr = fptr;
1715
1.35k
  intern->ref_type = REF_TYPE_FUNCTION;
1716
1.35k
  if (closure_obj) {
1717
931
    ZVAL_OBJ_COPY(&intern->obj, closure_obj);
1718
931
  } else {
1719
419
    ZVAL_UNDEF(&intern->obj);
1720
419
  }
1721
1.35k
  intern->ce = NULL;
1722
1.35k
}
1723
/* }}} */
1724
1725
/* {{{ Returns a string representation */
1726
ZEND_METHOD(ReflectionFunction, __toString)
1727
461
{
1728
461
  const reflection_object *intern;
1729
461
  const zend_function *fptr;
1730
461
  smart_str str = {0};
1731
1732
461
  ZEND_PARSE_PARAMETERS_NONE();
1733
461
  GET_REFLECTION_OBJECT_PTR(fptr);
1734
461
  _function_string(&str, fptr, NULL, "");
1735
461
  RETURN_STR(smart_str_extract(&str));
1736
461
}
1737
/* }}} */
1738
1739
/* {{{ Returns this function's name */
1740
ZEND_METHOD(ReflectionFunctionAbstract, getName)
1741
59
{
1742
59
  const reflection_object *intern;
1743
59
  const zend_function *fptr;
1744
1745
59
  ZEND_PARSE_PARAMETERS_NONE();
1746
1747
59
  GET_REFLECTION_OBJECT_PTR(fptr);
1748
59
  RETURN_STR_COPY(fptr->common.function_name);
1749
59
}
1750
/* }}} */
1751
1752
/* {{{ Returns whether this is a closure */
1753
ZEND_METHOD(ReflectionFunctionAbstract, isClosure)
1754
21
{
1755
21
  const reflection_object *intern;
1756
21
  const zend_function *fptr;
1757
1758
21
  ZEND_PARSE_PARAMETERS_NONE();
1759
1760
21
  GET_REFLECTION_OBJECT_PTR(fptr);
1761
21
  RETURN_BOOL(fptr->common.fn_flags & ZEND_ACC_CLOSURE);
1762
21
}
1763
/* }}} */
1764
1765
/* {{{ Returns this pointer bound to closure */
1766
ZEND_METHOD(ReflectionFunctionAbstract, getClosureThis)
1767
13
{
1768
13
  reflection_object *intern;
1769
1770
13
  ZEND_PARSE_PARAMETERS_NONE();
1771
1772
13
  GET_REFLECTION_OBJECT();
1773
13
  if (!Z_ISUNDEF(intern->obj)) {
1774
13
    zend_object *closure_this = zend_get_closure_this_ptr(&intern->obj);
1775
13
    if (closure_this) {
1776
12
      RETURN_OBJ_COPY(closure_this);
1777
12
    }
1778
13
  }
1779
13
}
1780
/* }}} */
1781
1782
/* {{{ Returns the scope associated to the closure */
1783
ZEND_METHOD(ReflectionFunctionAbstract, getClosureScopeClass)
1784
82
{
1785
82
  const reflection_object *intern;
1786
1787
82
  ZEND_PARSE_PARAMETERS_NONE();
1788
82
  GET_REFLECTION_OBJECT();
1789
82
  if (!Z_ISUNDEF(intern->obj)) {
1790
82
    const zend_function *closure_func = zend_get_closure_method_def(Z_OBJ(intern->obj));
1791
82
    if (closure_func && closure_func->common.scope) {
1792
64
      zend_reflection_class_factory(closure_func->common.scope, return_value);
1793
64
    }
1794
82
  }
1795
82
}
1796
/* }}} */
1797
1798
/* {{{ Returns the called scope associated to the closure */
1799
ZEND_METHOD(ReflectionFunctionAbstract, getClosureCalledClass)
1800
62
{
1801
62
  const reflection_object *intern;
1802
1803
62
  ZEND_PARSE_PARAMETERS_NONE();
1804
62
  GET_REFLECTION_OBJECT();
1805
62
  if (!Z_ISUNDEF(intern->obj)) {
1806
62
    zend_class_entry *called_scope;
1807
62
    zend_function *closure_func;
1808
62
    zend_object *object;
1809
62
    if (Z_OBJ_HANDLER(intern->obj, get_closure)
1810
62
      && Z_OBJ_HANDLER(intern->obj, get_closure)(Z_OBJ(intern->obj), &called_scope, &closure_func, &object, true) == SUCCESS
1811
62
      && closure_func && (called_scope || closure_func->common.scope)
1812
62
    ) {
1813
47
      zend_reflection_class_factory(called_scope ? called_scope : closure_func->common.scope, return_value);
1814
47
    }
1815
62
  }
1816
62
}
1817
/* }}} */
1818
1819
/* {{{ Returns an associative array containing the closures lexical scope variables */
1820
ZEND_METHOD(ReflectionFunctionAbstract, getClosureUsedVariables)
1821
77
{
1822
77
  const reflection_object *intern;
1823
1824
77
  ZEND_PARSE_PARAMETERS_NONE();
1825
77
  GET_REFLECTION_OBJECT();
1826
1827
77
  if (Z_ISUNDEF(intern->obj)) {
1828
0
    RETURN_EMPTY_ARRAY();
1829
0
  }
1830
1831
77
  const zend_function *closure_func = zend_get_closure_method_def(Z_OBJ(intern->obj));
1832
77
  if (closure_func == NULL ||
1833
77
    closure_func->type != ZEND_USER_FUNCTION ||
1834
77
    closure_func->op_array.static_variables == NULL
1835
77
  ) {
1836
46
    RETURN_EMPTY_ARRAY();
1837
46
  }
1838
1839
31
  const zend_op_array *ops = &closure_func->op_array;
1840
1841
31
  const HashTable *static_variables = ZEND_MAP_PTR_GET(ops->static_variables_ptr);
1842
1843
31
  if (!static_variables) {
1844
0
    RETURN_EMPTY_ARRAY();
1845
0
  }
1846
1847
31
  array_init(return_value);
1848
31
  const zend_op *opline = ops->opcodes + ops->num_args;
1849
31
  if (ops->fn_flags & ZEND_ACC_VARIADIC) {
1850
0
    opline++;
1851
0
  }
1852
1853
62
  for (; opline->opcode == ZEND_BIND_STATIC; opline++) {
1854
31
    if (!(opline->extended_value & (ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT))) {
1855
0
      continue;
1856
0
    }
1857
1858
31
    Bucket *bucket = (Bucket*)
1859
31
      (((char*)static_variables->arData) +
1860
31
      (opline->extended_value & ~(ZEND_BIND_REF|ZEND_BIND_IMPLICIT|ZEND_BIND_EXPLICIT)));
1861
1862
31
    if (Z_ISUNDEF(bucket->val)) {
1863
0
      continue;
1864
0
    }
1865
1866
31
    zend_hash_add_new(Z_ARRVAL_P(return_value), bucket->key, &bucket->val);
1867
31
    Z_TRY_ADDREF(bucket->val);
1868
31
  }
1869
31
} /* }}} */
1870
1871
/* {{{ Returns a dynamically created closure for the function */
1872
ZEND_METHOD(ReflectionFunction, getClosure)
1873
55
{
1874
55
  const reflection_object *intern;
1875
55
  zend_function *fptr;
1876
1877
55
  ZEND_PARSE_PARAMETERS_NONE();
1878
52
  GET_REFLECTION_OBJECT_PTR(fptr);
1879
1880
52
  if (!Z_ISUNDEF(intern->obj)) {
1881
    /* Closures are immutable objects */
1882
2
    RETURN_OBJ_COPY(Z_OBJ(intern->obj));
1883
50
  } else {
1884
50
    zend_create_fake_closure(return_value, fptr, NULL, NULL, NULL);
1885
50
  }
1886
52
}
1887
/* }}} */
1888
1889
/* {{{ Returns whether this is an internal function */
1890
ZEND_METHOD(ReflectionFunctionAbstract, isInternal)
1891
0
{
1892
0
  const reflection_object *intern;
1893
0
  const zend_function *fptr;
1894
1895
0
  ZEND_PARSE_PARAMETERS_NONE();
1896
0
  GET_REFLECTION_OBJECT_PTR(fptr);
1897
0
  RETURN_BOOL(fptr->type == ZEND_INTERNAL_FUNCTION);
1898
0
}
1899
/* }}} */
1900
1901
/* {{{ Returns whether this is a user-defined function */
1902
ZEND_METHOD(ReflectionFunctionAbstract, isUserDefined)
1903
0
{
1904
0
  const reflection_object *intern;
1905
0
  const zend_function *fptr;
1906
1907
0
  ZEND_PARSE_PARAMETERS_NONE();
1908
0
  GET_REFLECTION_OBJECT_PTR(fptr);
1909
0
  RETURN_BOOL(fptr->type == ZEND_USER_FUNCTION);
1910
0
}
1911
/* }}} */
1912
1913
/* {{{ Returns whether this function is an anonymous closure or not */
1914
ZEND_METHOD(ReflectionFunction, isAnonymous)
1915
34
{
1916
34
  const reflection_object *intern;
1917
34
  const zend_function *fptr;
1918
1919
34
  ZEND_PARSE_PARAMETERS_NONE();
1920
1921
34
  GET_REFLECTION_OBJECT_PTR(fptr);
1922
34
  RETURN_BOOL((fptr->common.fn_flags & (ZEND_ACC_CLOSURE | ZEND_ACC_FAKE_CLOSURE)) == ZEND_ACC_CLOSURE);
1923
34
}
1924
/* }}} */
1925
1926
/* {{{ Returns whether this function has been disabled or not */
1927
ZEND_METHOD(ReflectionFunction, isDisabled)
1928
3
{
1929
3
  ZEND_PARSE_PARAMETERS_NONE();
1930
1931
  /* A disabled function cannot be queried using Reflection. */
1932
3
  RETURN_FALSE;
1933
3
}
1934
/* }}} */
1935
1936
/* {{{ Returns the filename of the file this function was declared in */
1937
ZEND_METHOD(ReflectionFunctionAbstract, getFileName)
1938
0
{
1939
0
  const reflection_object *intern;
1940
0
  const zend_function *fptr;
1941
1942
0
  ZEND_PARSE_PARAMETERS_NONE();
1943
0
  GET_REFLECTION_OBJECT_PTR(fptr);
1944
0
  if (fptr->type == ZEND_USER_FUNCTION) {
1945
0
    RETURN_STR_COPY(fptr->op_array.filename);
1946
0
  }
1947
0
  RETURN_FALSE;
1948
0
}
1949
/* }}} */
1950
1951
/* {{{ Returns the line this function's declaration starts at */
1952
ZEND_METHOD(ReflectionFunctionAbstract, getStartLine)
1953
0
{
1954
0
  const reflection_object *intern;
1955
0
  const zend_function *fptr;
1956
1957
0
  ZEND_PARSE_PARAMETERS_NONE();
1958
0
  GET_REFLECTION_OBJECT_PTR(fptr);
1959
0
  if (fptr->type == ZEND_USER_FUNCTION) {
1960
0
    RETURN_LONG(fptr->op_array.line_start);
1961
0
  }
1962
0
  RETURN_FALSE;
1963
0
}
1964
/* }}} */
1965
1966
/* {{{ Returns the line this function's declaration ends at */
1967
ZEND_METHOD(ReflectionFunctionAbstract, getEndLine)
1968
0
{
1969
0
  const reflection_object *intern;
1970
0
  const zend_function *fptr;
1971
1972
0
  ZEND_PARSE_PARAMETERS_NONE();
1973
0
  GET_REFLECTION_OBJECT_PTR(fptr);
1974
0
  if (fptr->type == ZEND_USER_FUNCTION) {
1975
0
    RETURN_LONG(fptr->op_array.line_end);
1976
0
  }
1977
0
  RETURN_FALSE;
1978
0
}
1979
/* }}} */
1980
1981
/* {{{ Returns the doc comment for this function */
1982
ZEND_METHOD(ReflectionFunctionAbstract, getDocComment)
1983
20
{
1984
20
  const reflection_object *intern;
1985
20
  const zend_function *fptr;
1986
1987
20
  ZEND_PARSE_PARAMETERS_NONE();
1988
1989
20
  GET_REFLECTION_OBJECT_PTR(fptr);
1990
1991
20
  if (fptr->common.doc_comment) {
1992
2
    RETURN_STR_COPY(fptr->common.doc_comment);
1993
2
  }
1994
1995
18
  RETURN_FALSE;
1996
18
}
1997
/* }}} */
1998
1999
/* {{{ Returns the attributes of this function */
2000
ZEND_METHOD(ReflectionFunctionAbstract, getAttributes)
2001
487
{
2002
487
  const reflection_object *intern;
2003
487
  const zend_function *fptr;
2004
2005
487
  GET_REFLECTION_OBJECT_PTR(fptr);
2006
  
2007
487
  uint32_t target;
2008
487
  if (fptr->common.scope && (fptr->common.fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_FAKE_CLOSURE)) != ZEND_ACC_CLOSURE) {
2009
165
    target = ZEND_ATTRIBUTE_TARGET_METHOD;
2010
322
  } else {
2011
322
    target = ZEND_ATTRIBUTE_TARGET_FUNCTION;
2012
322
  }
2013
2014
487
  reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
2015
487
    fptr->common.attributes, 0, fptr->common.scope, target,
2016
487
    fptr->type == ZEND_USER_FUNCTION ? fptr->op_array.filename : NULL);
2017
487
}
2018
/* }}} */
2019
2020
/* {{{ Returns an associative array containing this function's static variables and their values */
2021
ZEND_METHOD(ReflectionFunctionAbstract, getStaticVariables)
2022
6
{
2023
6
  const reflection_object *intern;
2024
6
  zend_function *fptr;
2025
2026
6
  ZEND_PARSE_PARAMETERS_NONE();
2027
6
  GET_REFLECTION_OBJECT_PTR(fptr);
2028
2029
  /* Return an empty array in case no static variables exist */
2030
6
  if (fptr->type == ZEND_USER_FUNCTION && fptr->op_array.static_variables != NULL) {
2031
1
    array_init(return_value);
2032
1
    HashTable *ht = ZEND_MAP_PTR_GET(fptr->op_array.static_variables_ptr);
2033
1
    if (!ht) {
2034
1
      ht = zend_array_dup(fptr->op_array.static_variables);
2035
1
      ZEND_MAP_PTR_SET(fptr->op_array.static_variables_ptr, ht);
2036
1
    }
2037
1
    zend_hash_copy(Z_ARRVAL_P(return_value), ht, zval_add_ref);
2038
5
  } else {
2039
5
    RETURN_EMPTY_ARRAY();
2040
5
  }
2041
6
}
2042
/* }}} */
2043
2044
/* {{{ Invokes the function */
2045
ZEND_METHOD(ReflectionFunction, invoke)
2046
22
{
2047
22
  zval *params;
2048
22
  uint32_t num_args;
2049
22
  HashTable *named_params;
2050
22
  const reflection_object *intern;
2051
22
  zend_function *fptr;
2052
2053
66
  ZEND_PARSE_PARAMETERS_START(0, -1)
2054
66
    Z_PARAM_VARIADIC_WITH_NAMED(params, num_args, named_params)
2055
66
  ZEND_PARSE_PARAMETERS_END();
2056
2057
22
  GET_REFLECTION_OBJECT_PTR(fptr);
2058
2059
22
  zend_fcall_info_cache fcc;
2060
22
  fcc.function_handler = fptr;
2061
22
  fcc.called_scope = NULL;
2062
22
  fcc.object = NULL;
2063
2064
22
  if (!Z_ISUNDEF(intern->obj)) {
2065
15
    Z_OBJ_HT(intern->obj)->get_closure(
2066
15
      Z_OBJ(intern->obj), &fcc.called_scope, &fcc.function_handler, &fcc.object, false);
2067
15
  }
2068
2069
22
  zval retval;
2070
22
  zend_call_known_fcc(&fcc, &retval, num_args, params, named_params);
2071
2072
22
  if (Z_ISREF(retval)) {
2073
5
    zend_unwrap_reference(&retval);
2074
5
  }
2075
22
  RETURN_COPY_VALUE(&retval);
2076
22
}
2077
/* }}} */
2078
2079
/* {{{ Invokes the function and pass its arguments as array. */
2080
ZEND_METHOD(ReflectionFunction, invokeArgs)
2081
24
{
2082
24
  const reflection_object *intern;
2083
24
  zend_function *fptr;
2084
24
  HashTable *params;
2085
2086
24
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "h", &params) == FAILURE) {
2087
1
    RETURN_THROWS();
2088
1
  }
2089
2090
23
  GET_REFLECTION_OBJECT_PTR(fptr);
2091
2092
23
  zend_fcall_info_cache fcc;
2093
23
  fcc.function_handler = fptr;
2094
23
  fcc.called_scope = NULL;
2095
23
  fcc.object = NULL;
2096
2097
23
  if (!Z_ISUNDEF(intern->obj)) {
2098
17
    Z_OBJ_HT(intern->obj)->get_closure(
2099
17
      Z_OBJ(intern->obj), &fcc.called_scope, &fcc.function_handler, &fcc.object, false);
2100
17
  }
2101
2102
23
  zval retval;
2103
23
  zend_call_known_fcc(&fcc, &retval, /* num_params */ 0, /* params */ NULL, params);
2104
2105
23
  if (Z_ISREF(retval)) {
2106
5
    zend_unwrap_reference(&retval);
2107
5
  }
2108
23
  RETURN_COPY_VALUE(&retval);
2109
23
}
2110
/* }}} */
2111
2112
/* {{{ Gets whether this function returns a reference */
2113
ZEND_METHOD(ReflectionFunctionAbstract, returnsReference)
2114
2
{
2115
2
  const reflection_object *intern;
2116
2
  const zend_function *fptr;
2117
2118
2
  ZEND_PARSE_PARAMETERS_NONE();
2119
2120
2
  GET_REFLECTION_OBJECT_PTR(fptr);
2121
2122
2
  RETURN_BOOL((fptr->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) != 0);
2123
2
}
2124
/* }}} */
2125
2126
/* {{{ Gets the number of parameters */
2127
ZEND_METHOD(ReflectionFunctionAbstract, getNumberOfParameters)
2128
0
{
2129
0
  const reflection_object *intern;
2130
0
  const zend_function *fptr;
2131
2132
0
  ZEND_PARSE_PARAMETERS_NONE();
2133
2134
0
  GET_REFLECTION_OBJECT_PTR(fptr);
2135
2136
0
  uint32_t num_args = fptr->common.num_args;
2137
0
  if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
2138
0
    num_args++;
2139
0
  }
2140
2141
0
  RETURN_LONG(num_args);
2142
0
}
2143
/* }}} */
2144
2145
/* {{{ Gets the number of required parameters */
2146
ZEND_METHOD(ReflectionFunctionAbstract, getNumberOfRequiredParameters)
2147
0
{
2148
0
  const reflection_object *intern;
2149
0
  const zend_function *fptr;
2150
2151
0
  ZEND_PARSE_PARAMETERS_NONE();
2152
2153
0
  GET_REFLECTION_OBJECT_PTR(fptr);
2154
2155
0
  RETURN_LONG(fptr->common.required_num_args);
2156
0
}
2157
/* }}} */
2158
2159
/* {{{ Returns an array of parameter objects for this function */
2160
ZEND_METHOD(ReflectionFunctionAbstract, getParameters)
2161
215
{
2162
215
  reflection_object *intern;
2163
215
  zend_function *fptr;
2164
2165
215
  ZEND_PARSE_PARAMETERS_NONE();
2166
2167
215
  GET_REFLECTION_OBJECT_PTR(fptr);
2168
2169
215
  const zend_arg_info *arg_info = fptr->common.arg_info;
2170
215
  uint32_t num_args = fptr->common.num_args;
2171
215
  if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
2172
23
    num_args++;
2173
23
  }
2174
2175
215
  if (!num_args) {
2176
0
    RETURN_EMPTY_ARRAY();
2177
0
  }
2178
2179
215
  array_init(return_value);
2180
634
  for (uint32_t i = 0; i < num_args; i++) {
2181
419
    zval parameter;
2182
2183
419
    reflection_parameter_factory(
2184
419
      _copy_function(fptr),
2185
419
      Z_ISUNDEF(intern->obj) ? NULL : &intern->obj,
2186
419
      arg_info,
2187
419
      i,
2188
419
      i < fptr->common.required_num_args,
2189
419
      &parameter
2190
419
    );
2191
419
    zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &parameter);
2192
2193
419
    arg_info++;
2194
419
  }
2195
215
}
2196
/* }}} */
2197
2198
/* {{{ Returns NULL or the extension the function belongs to */
2199
ZEND_METHOD(ReflectionFunctionAbstract, getExtension)
2200
4
{
2201
4
  const reflection_object *intern;
2202
4
  const zend_function *fptr;
2203
2204
4
  ZEND_PARSE_PARAMETERS_NONE();
2205
2206
4
  GET_REFLECTION_OBJECT_PTR(fptr);
2207
2208
4
  if (fptr->type != ZEND_INTERNAL_FUNCTION) {
2209
1
    RETURN_NULL();
2210
1
  }
2211
2212
3
  const zend_internal_function *internal = (zend_internal_function *)fptr;
2213
3
  if (internal->module) {
2214
3
    reflection_extension_factory(return_value, internal->module);
2215
3
  } else {
2216
0
    RETURN_NULL();
2217
0
  }
2218
3
}
2219
/* }}} */
2220
2221
/* {{{ Returns false or the name of the extension the function belongs to */
2222
ZEND_METHOD(ReflectionFunctionAbstract, getExtensionName)
2223
5
{
2224
5
  const reflection_object *intern;
2225
5
  const zend_function *fptr;
2226
2227
5
  ZEND_PARSE_PARAMETERS_NONE();
2228
2229
5
  GET_REFLECTION_OBJECT_PTR(fptr);
2230
2231
5
  if (fptr->type != ZEND_INTERNAL_FUNCTION) {
2232
1
    RETURN_FALSE;
2233
1
  }
2234
2235
4
  const zend_internal_function *internal = (zend_internal_function *)fptr;
2236
4
  if (internal->module) {
2237
4
    RETURN_STRING(internal->module->name);
2238
4
  } else {
2239
0
    RETURN_FALSE;
2240
0
  }
2241
4
}
2242
/* }}} */
2243
2244
/* {{{ */
2245
ZEND_METHOD(ReflectionGenerator, __construct)
2246
8
{
2247
8
  zval *generator;
2248
2249
8
  zval *object = ZEND_THIS;
2250
8
  reflection_object *intern = Z_REFLECTION_P(object);
2251
2252
8
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &generator, zend_ce_generator) == FAILURE) {
2253
5
    RETURN_THROWS();
2254
5
  }
2255
2256
3
  if (intern->ce) {
2257
0
    zval_ptr_dtor(&intern->obj);
2258
0
  }
2259
2260
3
  intern->ref_type = REF_TYPE_GENERATOR;
2261
3
  ZVAL_OBJ_COPY(&intern->obj, Z_OBJ_P(generator));
2262
3
  intern->ce = zend_ce_generator;
2263
3
}
2264
/* }}} */
2265
2266
#define REFLECTION_CHECK_VALID_GENERATOR(ex) \
2267
2
  if (!ex) { \
2268
1
    zend_throw_exception(reflection_exception_ptr, "Cannot fetch information from a closed Generator", 0); \
2269
1
    RETURN_THROWS(); \
2270
1
  }
2271
2272
/* {{{ */
2273
ZEND_METHOD(ReflectionGenerator, getTrace)
2274
2
{
2275
2
  zend_long options = DEBUG_BACKTRACE_PROVIDE_OBJECT;
2276
2
  zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2277
2
  zend_execute_data *ex_backup = EG(current_execute_data);
2278
2
  zend_execute_data *ex = generator->execute_data;
2279
2
  zend_execute_data *root_prev = NULL;
2280
2281
2
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &options) == FAILURE) {
2282
0
    RETURN_THROWS();
2283
0
  }
2284
2285
2
  REFLECTION_CHECK_VALID_GENERATOR(ex)
2286
2287
1
  zend_generator *root_generator = zend_generator_get_current(generator);
2288
2289
1
  zend_execute_data *cur_prev = generator->execute_data->prev_execute_data;
2290
1
  if (generator == root_generator) {
2291
0
    generator->execute_data->prev_execute_data = NULL;
2292
1
  } else {
2293
1
    root_prev = root_generator->execute_data->prev_execute_data;
2294
1
    generator->execute_fake.prev_execute_data = NULL;
2295
1
    root_generator->execute_data->prev_execute_data = &generator->execute_fake;
2296
1
  }
2297
2298
1
  EG(current_execute_data) = root_generator->execute_data;
2299
1
  zend_fetch_debug_backtrace(return_value, 0, options, 0);
2300
1
  EG(current_execute_data) = ex_backup;
2301
2302
1
  root_generator->execute_data->prev_execute_data = root_prev;
2303
1
  generator->execute_data->prev_execute_data = cur_prev;
2304
1
}
2305
/* }}} */
2306
2307
/* {{{ */
2308
ZEND_METHOD(ReflectionGenerator, getExecutingLine)
2309
0
{
2310
0
  const zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2311
0
  const zend_execute_data *ex = generator->execute_data;
2312
2313
0
  ZEND_PARSE_PARAMETERS_NONE();
2314
2315
0
  REFLECTION_CHECK_VALID_GENERATOR(ex)
2316
2317
0
  ZVAL_LONG(return_value, ex->opline->lineno);
2318
0
}
2319
/* }}} */
2320
2321
/* {{{ */
2322
ZEND_METHOD(ReflectionGenerator, getExecutingFile)
2323
0
{
2324
0
  const zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2325
0
  const zend_execute_data *ex = generator->execute_data;
2326
2327
0
  ZEND_PARSE_PARAMETERS_NONE();
2328
2329
0
  REFLECTION_CHECK_VALID_GENERATOR(ex)
2330
2331
0
  ZVAL_STR_COPY(return_value, ex->func->op_array.filename);
2332
0
}
2333
/* }}} */
2334
2335
/* {{{ */
2336
ZEND_METHOD(ReflectionGenerator, getFunction)
2337
0
{
2338
0
  const zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2339
0
  zend_function *func = generator->func;
2340
2341
0
  ZEND_PARSE_PARAMETERS_NONE();
2342
2343
0
  if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
2344
0
    zval closure;
2345
0
    ZVAL_OBJ(&closure, ZEND_CLOSURE_OBJECT(func));
2346
0
    reflection_function_factory(func, &closure, return_value);
2347
0
  } else if (func->common.scope) {
2348
0
    reflection_method_factory(func->common.scope, func, NULL, return_value);
2349
0
  } else {
2350
0
    reflection_function_factory(func, NULL, return_value);
2351
0
  }
2352
0
}
2353
/* }}} */
2354
2355
/* {{{ */
2356
ZEND_METHOD(ReflectionGenerator, getThis)
2357
0
{
2358
0
  const zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2359
0
  zend_execute_data *ex = generator->execute_data;
2360
2361
0
  ZEND_PARSE_PARAMETERS_NONE();
2362
2363
0
  REFLECTION_CHECK_VALID_GENERATOR(ex)
2364
2365
0
  if (Z_TYPE(ex->This) == IS_OBJECT) {
2366
0
    RETURN_OBJ_COPY(Z_OBJ(ex->This));
2367
0
  } else {
2368
0
    RETURN_NULL();
2369
0
  }
2370
0
}
2371
/* }}} */
2372
2373
/* {{{ */
2374
ZEND_METHOD(ReflectionGenerator, getExecutingGenerator)
2375
0
{
2376
0
  zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2377
0
  zend_execute_data *ex = generator->execute_data;
2378
2379
0
  ZEND_PARSE_PARAMETERS_NONE();
2380
2381
0
  REFLECTION_CHECK_VALID_GENERATOR(ex)
2382
2383
0
  zend_generator *current = zend_generator_get_current(generator);
2384
0
  RETURN_OBJ_COPY(&current->std);
2385
0
}
2386
/* }}} */
2387
2388
ZEND_METHOD(ReflectionGenerator, isClosed)
2389
0
{
2390
0
  const zend_generator *generator = (zend_generator *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
2391
0
  zend_execute_data *ex = generator->execute_data;
2392
2393
0
  ZEND_PARSE_PARAMETERS_NONE();
2394
2395
0
  RETURN_BOOL(ex == NULL);
2396
0
}
2397
2398
/* {{{ Constructor. Throws an Exception in case the given method does not exist */
2399
ZEND_METHOD(ReflectionParameter, __construct)
2400
68
{
2401
68
  parameter_reference *ref;
2402
68
  zval *reference;
2403
68
  zend_string *arg_name = NULL;
2404
68
  zend_long position;
2405
68
  zend_function *fptr;
2406
68
  zend_class_entry *ce = NULL;
2407
68
  bool is_closure = false;
2408
2409
200
  ZEND_PARSE_PARAMETERS_START(2, 2)
2410
256
    Z_PARAM_ZVAL(reference)
2411
320
    Z_PARAM_STR_OR_LONG(arg_name, position)
2412
320
  ZEND_PARSE_PARAMETERS_END();
2413
2414
64
  zval *object = ZEND_THIS;
2415
64
  reflection_object *intern = Z_REFLECTION_P(object);
2416
2417
  /* First, find the function */
2418
64
  switch (Z_TYPE_P(reference)) {
2419
17
    case IS_STRING: {
2420
17
      zend_string *fname = Z_STR_P(reference);
2421
17
      fptr = zend_fetch_function(fname);
2422
17
      if (!fptr) {
2423
1
        zend_throw_exception_ex(reflection_exception_ptr, 0,
2424
1
          "Function %pS() does not exist", fname);
2425
1
        RETURN_THROWS();
2426
1
      }
2427
16
      ce = fptr->common.scope;
2428
16
      break;
2429
17
    }
2430
2431
41
    case IS_ARRAY: {
2432
41
      zval *classref;
2433
41
      zval *method;
2434
41
      zend_string *name;
2435
2436
41
      if (((classref = zend_hash_index_find(Z_ARRVAL_P(reference), 0)) == NULL)
2437
41
        || ((method = zend_hash_index_find(Z_ARRVAL_P(reference), 1)) == NULL)
2438
41
      ) {
2439
3
        zend_throw_exception(reflection_exception_ptr, "Expected array($object, $method) or array($classname, $method)", 0);
2440
3
        RETURN_THROWS();
2441
3
      }
2442
2443
38
      if (Z_TYPE_P(classref) == IS_OBJECT) {
2444
0
        ce = Z_OBJCE_P(classref);
2445
38
      } else {
2446
38
        name = zval_try_get_string(classref);
2447
38
        if (UNEXPECTED(!name)) {
2448
0
          return;
2449
0
        }
2450
38
        if ((ce = zend_lookup_class(name)) == NULL) {
2451
1
          zend_throw_exception_ex(reflection_exception_ptr, 0,
2452
1
              "Class \"%pS\" does not exist", name);
2453
1
          zend_string_release(name);
2454
1
          RETURN_THROWS();
2455
1
        }
2456
37
        zend_string_release(name);
2457
37
      }
2458
2459
37
      name = zval_try_get_string(method);
2460
37
      if (UNEXPECTED(!name)) {
2461
0
        return;
2462
0
      }
2463
2464
37
      zend_string *lcname = zend_string_tolower(name);
2465
37
      if (Z_TYPE_P(classref) == IS_OBJECT && is_closure_invoke(ce, lcname)
2466
0
        && (fptr = zend_get_closure_invoke_method(Z_OBJ_P(classref))) != NULL)
2467
0
      {
2468
        /* nothing to do. don't set is_closure since is the invoke handler,
2469
          not the closure itself */
2470
37
      } else if ((fptr = zend_hash_find_ptr(&ce->function_table, lcname)) == NULL) {
2471
11
        zend_throw_exception_ex(reflection_exception_ptr, 0,
2472
11
          "Method %pS::%pS() does not exist", ce->name, name);
2473
11
        zend_string_release(name);
2474
11
        zend_string_release(lcname);
2475
11
        RETURN_THROWS();
2476
11
      }
2477
26
      zend_string_release(name);
2478
26
      zend_string_release(lcname);
2479
26
      break;
2480
37
    }
2481
2482
6
    case IS_OBJECT: {
2483
6
      ce = Z_OBJCE_P(reference);
2484
2485
      // No need for instanceof_function, the Closure class is final
2486
6
      if (ce == zend_ce_closure) {
2487
6
        fptr = (zend_function *)zend_get_closure_method_def(Z_OBJ_P(reference));
2488
6
        Z_ADDREF_P(reference);
2489
6
        is_closure = true;
2490
6
      } else if ((fptr = zend_hash_find_ptr(&ce->function_table, ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE))) == NULL) {
2491
0
        zend_throw_exception_ex(reflection_exception_ptr, 0,
2492
0
          "Method %pS::%s() does not exist", ce->name, ZEND_INVOKE_FUNC_NAME);
2493
0
        RETURN_THROWS();
2494
0
      }
2495
6
      break;
2496
6
    }
2497
2498
6
    default:
2499
0
      zend_argument_error(reflection_exception_ptr, 1, "must be a string, an array(class, method), or a callable object, %s given", zend_zval_value_name(reference));
2500
0
      RETURN_THROWS();
2501
64
  }
2502
2503
  /* Now, search for the parameter */
2504
48
  const zend_arg_info *arg_info = fptr->common.arg_info;
2505
48
  uint32_t num_args = fptr->common.num_args;
2506
48
  if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
2507
0
    num_args++;
2508
0
  }
2509
48
  if (arg_name != NULL) {
2510
40
    position = -1;
2511
2512
46
    for (uint32_t i = 0; i < num_args; i++) {
2513
40
      if (arg_info[i].name
2514
40
        && zend_string_equals(arg_name, arg_info[i].name)
2515
40
      ) {
2516
34
        position = i;
2517
34
        break;
2518
34
      }
2519
40
    }
2520
40
    if (position == -1) {
2521
6
      zend_throw_exception(reflection_exception_ptr, "The parameter specified by its name could not be found", 0);
2522
6
      goto failure;
2523
6
    }
2524
40
  } else {
2525
8
    if (position < 0) {
2526
0
      zend_argument_value_error(2, "must be greater than or equal to 0");
2527
0
      goto failure;
2528
0
    }
2529
8
    if (position >= num_args) {
2530
0
      zend_throw_exception(reflection_exception_ptr, "The parameter specified by its offset could not be found", 0);
2531
0
      goto failure;
2532
0
    }
2533
8
  }
2534
2535
42
  if (intern->ptr) {
2536
5
    reflection_free_parameter_reference(intern->ptr);
2537
5
  }
2538
2539
42
  ref = (parameter_reference*) emalloc(sizeof(parameter_reference));
2540
42
  ref->arg_info = &arg_info[position];
2541
42
  ref->offset = (uint32_t)position;
2542
42
  ref->required = (uint32_t)position < fptr->common.required_num_args;
2543
42
  ref->fptr = fptr;
2544
  /* TODO: copy fptr */
2545
42
  intern->ptr = ref;
2546
42
  intern->ref_type = REF_TYPE_PARAMETER;
2547
42
  intern->ce = ce;
2548
42
  zval_ptr_dtor(&intern->obj);
2549
42
  if (reference && is_closure) {
2550
6
    ZVAL_COPY_VALUE(&intern->obj, reference);
2551
36
  } else {
2552
36
    ZVAL_UNDEF(&intern->obj);
2553
36
  }
2554
2555
42
  zval *prop_name = reflection_prop_name(object);
2556
42
  zval_ptr_dtor(prop_name);
2557
42
  ZVAL_STR_COPY(prop_name, arg_info[position].name);
2558
42
  return;
2559
2560
6
failure:
2561
6
  if (fptr->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
2562
0
    zend_string_release_ex(fptr->common.function_name, false);
2563
0
    zend_free_trampoline(fptr);
2564
0
  }
2565
6
  if (is_closure) {
2566
0
    zval_ptr_dtor(reference);
2567
0
  }
2568
6
  RETURN_THROWS();
2569
6
}
2570
/* }}} */
2571
2572
/* {{{ Returns a string representation */
2573
ZEND_METHOD(ReflectionParameter, __toString)
2574
23
{
2575
23
  const reflection_object *intern;
2576
23
  const parameter_reference *param;
2577
23
  smart_str str = {0};
2578
2579
23
  ZEND_PARSE_PARAMETERS_NONE();
2580
23
  GET_REFLECTION_OBJECT_PTR(param);
2581
23
  _parameter_string(&str, param->fptr, param->arg_info, param->offset, param->required);
2582
23
  RETURN_STR(smart_str_extract(&str));
2583
23
}
2584
2585
/* }}} */
2586
2587
/* {{{ Returns the doc comment for this parameter */
2588
ZEND_METHOD(ReflectionParameter, getDocComment)
2589
0
{
2590
0
  const reflection_object *intern;
2591
0
  const parameter_reference *param;
2592
2593
0
  ZEND_PARSE_PARAMETERS_NONE();
2594
2595
0
  GET_REFLECTION_OBJECT_PTR(param);
2596
0
  if (param->arg_info->doc_comment) {
2597
0
    RETURN_STR_COPY(param->arg_info->doc_comment);
2598
0
  }
2599
0
  RETURN_FALSE;
2600
0
}
2601
/* }}} */
2602
2603
/* {{{ Returns this parameter's name */
2604
ZEND_METHOD(ReflectionParameter, getName)
2605
4
{
2606
4
  const reflection_object *intern;
2607
4
  const parameter_reference *param;
2608
2609
4
  ZEND_PARSE_PARAMETERS_NONE();
2610
2611
4
  GET_REFLECTION_OBJECT_PTR(param);
2612
4
  RETURN_STR_COPY(param->arg_info->name);
2613
4
}
2614
/* }}} */
2615
2616
/* {{{ Returns the ReflectionFunction for the function of this parameter */
2617
ZEND_METHOD(ReflectionParameter, getDeclaringFunction)
2618
3
{
2619
3
  reflection_object *intern;
2620
3
  const parameter_reference *param;
2621
2622
3
  ZEND_PARSE_PARAMETERS_NONE();
2623
3
  GET_REFLECTION_OBJECT_PTR(param);
2624
2625
3
  if (!param->fptr->common.scope) {
2626
2
    reflection_function_factory(_copy_function(param->fptr), Z_ISUNDEF(intern->obj)? NULL : &intern->obj, return_value);
2627
2
  } else {
2628
1
    reflection_method_factory(param->fptr->common.scope, _copy_function(param->fptr), Z_ISUNDEF(intern->obj)? NULL : &intern->obj, return_value);
2629
1
  }
2630
3
}
2631
/* }}} */
2632
2633
/* {{{ Returns in which class this parameter is defined (not the type of the parameter) */
2634
ZEND_METHOD(ReflectionParameter, getDeclaringClass)
2635
0
{
2636
0
  const reflection_object *intern;
2637
0
  const parameter_reference *param;
2638
2639
0
  ZEND_PARSE_PARAMETERS_NONE();
2640
0
  GET_REFLECTION_OBJECT_PTR(param);
2641
2642
0
  if (param->fptr->common.scope) {
2643
0
    zend_reflection_class_factory(param->fptr->common.scope, return_value);
2644
0
  }
2645
0
}
2646
/* }}} */
2647
2648
/* {{{ Returns this parameters's class hint or NULL if there is none */
2649
ZEND_METHOD(ReflectionParameter, getClass)
2650
17
{
2651
17
  const reflection_object *intern;
2652
17
  const parameter_reference *param;
2653
2654
17
  ZEND_PARSE_PARAMETERS_NONE();
2655
17
  GET_REFLECTION_OBJECT_PTR(param);
2656
2657
  // TODO: This is going to return null for union types, which is rather odd.
2658
17
  if (ZEND_TYPE_HAS_NAME(param->arg_info->type)) {
2659
    /* Class name is stored as a string, we might also get "self" or "parent"
2660
     * - For "self", simply use the function scope. If scope is NULL then
2661
     *   the function is global and thus self does not make any sense
2662
     *
2663
     * - For "parent", use the function scope's parent. If scope is NULL then
2664
     *   the function is global and thus parent does not make any sense.
2665
     *   If the parent is NULL then the class does not extend anything and
2666
     *   thus parent does not make any sense, either.
2667
     *
2668
     * TODO: Think about moving these checks to the compiler or some sort of
2669
     * lint-mode.
2670
     */
2671
12
    zend_class_entry *ce;
2672
12
    zend_string *class_name = ZEND_TYPE_NAME(param->arg_info->type);
2673
12
    if (zend_string_equals_ci(class_name, ZSTR_KNOWN(ZEND_STR_SELF))) {
2674
0
      ce = param->fptr->common.scope;
2675
0
      if (!ce) {
2676
0
        zend_throw_exception_ex(reflection_exception_ptr, 0,
2677
0
          "Parameter uses \"self\" as type but function is not a class member");
2678
0
        RETURN_THROWS();
2679
0
      }
2680
12
    } else if (zend_string_equals_ci(class_name, ZSTR_KNOWN(ZEND_STR_PARENT))) {
2681
0
      ce = param->fptr->common.scope;
2682
0
      if (!ce) {
2683
0
        zend_throw_exception_ex(reflection_exception_ptr, 0,
2684
0
          "Parameter uses \"parent\" as type but function is not a class member");
2685
0
        RETURN_THROWS();
2686
0
      }
2687
0
      if (!ce->parent) {
2688
0
        zend_throw_exception_ex(reflection_exception_ptr, 0,
2689
0
          "Parameter uses \"parent\" as type although class does not have a parent");
2690
0
        RETURN_THROWS();
2691
0
      }
2692
0
      ce = ce->parent;
2693
12
    } else {
2694
12
      ce = zend_lookup_class(class_name);
2695
12
      if (!ce) {
2696
0
        zend_throw_exception_ex(reflection_exception_ptr, 0,
2697
0
          "Class \"%pS\" does not exist", class_name);
2698
0
        RETURN_THROWS();
2699
0
      }
2700
12
    }
2701
12
    zend_reflection_class_factory(ce, return_value);
2702
12
  }
2703
17
}
2704
/* }}} */
2705
2706
/* {{{ Returns whether parameter has a type */
2707
ZEND_METHOD(ReflectionParameter, hasType)
2708
83
{
2709
83
  const reflection_object *intern;
2710
83
  const parameter_reference *param;
2711
2712
83
  ZEND_PARSE_PARAMETERS_NONE();
2713
83
  GET_REFLECTION_OBJECT_PTR(param);
2714
2715
83
  RETVAL_BOOL(ZEND_TYPE_IS_SET(param->arg_info->type));
2716
83
}
2717
/* }}} */
2718
2719
/* {{{ Returns the type associated with the parameter */
2720
ZEND_METHOD(ReflectionParameter, getType)
2721
76
{
2722
76
  const reflection_object *intern;
2723
76
  const parameter_reference *param;
2724
2725
76
  ZEND_PARSE_PARAMETERS_NONE();
2726
76
  GET_REFLECTION_OBJECT_PTR(param);
2727
2728
76
  if (!ZEND_TYPE_IS_SET(param->arg_info->type)) {
2729
0
    RETURN_NULL();
2730
0
  }
2731
76
  reflection_type_factory(param->arg_info->type, return_value, true);
2732
76
}
2733
/* }}} */
2734
2735
/* {{{ Returns whether parameter MUST be an array */
2736
ZEND_METHOD(ReflectionParameter, isArray)
2737
5
{
2738
5
  const reflection_object *intern;
2739
5
  const parameter_reference *param;
2740
2741
5
  ZEND_PARSE_PARAMETERS_NONE();
2742
4
  GET_REFLECTION_OBJECT_PTR(param);
2743
2744
  /* BC For iterable */
2745
4
  if (ZEND_TYPE_IS_ITERABLE_FALLBACK(param->arg_info->type)) {
2746
1
    RETURN_FALSE;
2747
1
  }
2748
2749
3
  uint32_t type_mask = ZEND_TYPE_PURE_MASK_WITHOUT_NULL(param->arg_info->type);
2750
3
  RETVAL_BOOL(type_mask == MAY_BE_ARRAY);
2751
3
}
2752
/* }}} */
2753
2754
/* {{{ Returns whether parameter MUST be callable */
2755
ZEND_METHOD(ReflectionParameter, isCallable)
2756
15
{
2757
15
  const reflection_object *intern;
2758
15
  const parameter_reference *param;
2759
2760
15
  ZEND_PARSE_PARAMETERS_NONE();
2761
15
  GET_REFLECTION_OBJECT_PTR(param);
2762
2763
15
  uint32_t type_mask = ZEND_TYPE_PURE_MASK_WITHOUT_NULL(param->arg_info->type);
2764
15
  RETVAL_BOOL(type_mask == MAY_BE_CALLABLE);
2765
15
}
2766
/* }}} */
2767
2768
/* {{{ Returns whether NULL is allowed as this parameter's value */
2769
ZEND_METHOD(ReflectionParameter, allowsNull)
2770
0
{
2771
0
  const reflection_object *intern;
2772
0
  const parameter_reference *param;
2773
2774
0
  ZEND_PARSE_PARAMETERS_NONE();
2775
0
  GET_REFLECTION_OBJECT_PTR(param);
2776
2777
0
  RETVAL_BOOL(!ZEND_TYPE_IS_SET(param->arg_info->type)
2778
0
    || ZEND_TYPE_ALLOW_NULL(param->arg_info->type));
2779
0
}
2780
/* }}} */
2781
2782
/* {{{ Returns whether this parameter is passed to by reference */
2783
ZEND_METHOD(ReflectionParameter, isPassedByReference)
2784
0
{
2785
0
  const reflection_object *intern;
2786
0
  const parameter_reference *param;
2787
2788
0
  ZEND_PARSE_PARAMETERS_NONE();
2789
0
  GET_REFLECTION_OBJECT_PTR(param);
2790
2791
0
  RETVAL_BOOL(ZEND_ARG_SEND_MODE(param->arg_info));
2792
0
}
2793
/* }}} */
2794
2795
/* {{{ Returns whether this parameter can be passed by value */
2796
ZEND_METHOD(ReflectionParameter, canBePassedByValue)
2797
0
{
2798
0
  const reflection_object *intern;
2799
0
  const parameter_reference *param;
2800
2801
0
  ZEND_PARSE_PARAMETERS_NONE();
2802
0
  GET_REFLECTION_OBJECT_PTR(param);
2803
2804
  /* true if it's ZEND_SEND_BY_VAL or ZEND_SEND_PREFER_REF */
2805
0
  RETVAL_BOOL(ZEND_ARG_SEND_MODE(param->arg_info) != ZEND_SEND_BY_REF);
2806
0
}
2807
/* }}} */
2808
2809
/* {{{ Get parameter attributes. */
2810
ZEND_METHOD(ReflectionParameter, getAttributes)
2811
93
{
2812
93
  const reflection_object *intern;
2813
93
  const parameter_reference *param;
2814
2815
93
  GET_REFLECTION_OBJECT_PTR(param);
2816
2817
93
  HashTable *attributes = param->fptr->common.attributes;
2818
93
  zend_class_entry *scope = param->fptr->common.scope;
2819
2820
93
  reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
2821
93
    attributes, param->offset + 1, scope, ZEND_ATTRIBUTE_TARGET_PARAMETER,
2822
93
    param->fptr->type == ZEND_USER_FUNCTION ? param->fptr->op_array.filename : NULL);
2823
93
}
2824
2825
/* {{{ Returns the index of the parameter, starting from 0 */
2826
ZEND_METHOD(ReflectionParameter, getPosition)
2827
2
{
2828
2
  const reflection_object *intern;
2829
2
  const parameter_reference *param;
2830
2831
2
  ZEND_PARSE_PARAMETERS_NONE();
2832
2
  GET_REFLECTION_OBJECT_PTR(param);
2833
2834
2
  RETVAL_LONG(param->offset);
2835
2
}
2836
/* }}} */
2837
2838
/* {{{ Returns whether this parameter is an optional parameter */
2839
ZEND_METHOD(ReflectionParameter, isOptional)
2840
109
{
2841
109
  const reflection_object *intern;
2842
109
  const parameter_reference *param;
2843
2844
109
  ZEND_PARSE_PARAMETERS_NONE();
2845
109
  GET_REFLECTION_OBJECT_PTR(param);
2846
2847
109
  RETVAL_BOOL(!param->required);
2848
109
}
2849
/* }}} */
2850
2851
/* {{{ Returns whether the default value of this parameter is available */
2852
ZEND_METHOD(ReflectionParameter, isDefaultValueAvailable)
2853
20
{
2854
20
  const reflection_object *intern;
2855
20
  const parameter_reference *param;
2856
2857
20
  ZEND_PARSE_PARAMETERS_NONE();
2858
2859
19
  GET_REFLECTION_OBJECT_PTR(param);
2860
2861
19
  if (param->fptr->type == ZEND_INTERNAL_FUNCTION) {
2862
9
    RETURN_BOOL(param->arg_info->default_value);
2863
10
  } else {
2864
10
    const zval *default_value = get_default_from_recv((const zend_op_array *)param->fptr, param->offset);
2865
10
    RETURN_BOOL(default_value != NULL);
2866
10
  }
2867
19
}
2868
/* }}} */
2869
2870
/* {{{ Returns the default value of this parameter or throws an exception */
2871
ZEND_METHOD(ReflectionParameter, getDefaultValue)
2872
4
{
2873
4
  const reflection_object *intern;
2874
4
  const parameter_reference *param;
2875
2876
4
  ZEND_PARSE_PARAMETERS_NONE();
2877
2878
4
  GET_REFLECTION_OBJECT_PTR(param);
2879
2880
4
  if (get_parameter_default(return_value, param) == FAILURE) {
2881
1
    zend_throw_exception_ex(reflection_exception_ptr, 0,
2882
1
      "Internal error: Failed to retrieve the default value");
2883
1
    RETURN_THROWS();
2884
1
  }
2885
2886
3
  if (Z_TYPE_P(return_value) == IS_CONSTANT_AST) {
2887
0
    zval_update_constant_ex(return_value, param->fptr->common.scope);
2888
0
  }
2889
3
}
2890
/* }}} */
2891
2892
/* {{{ Returns whether the default value of this parameter is constant */
2893
ZEND_METHOD(ReflectionParameter, isDefaultValueConstant)
2894
1
{
2895
1
  const reflection_object *intern;
2896
1
  const parameter_reference *param;
2897
2898
1
  ZEND_PARSE_PARAMETERS_NONE();
2899
2900
1
  GET_REFLECTION_OBJECT_PTR(param);
2901
2902
1
  zval default_value;
2903
1
  if (get_parameter_default(&default_value, param) == FAILURE) {
2904
0
    zend_throw_exception_ex(reflection_exception_ptr, 0,
2905
0
      "Internal error: Failed to retrieve the default value");
2906
0
    RETURN_THROWS();
2907
0
  }
2908
2909
1
  if (Z_TYPE(default_value) == IS_CONSTANT_AST) {
2910
0
    const zend_ast *ast = Z_ASTVAL(default_value);
2911
0
    RETVAL_BOOL(ast->kind == ZEND_AST_CONSTANT
2912
0
      || ast->kind == ZEND_AST_CONSTANT_CLASS
2913
0
      || ast->kind == ZEND_AST_CLASS_CONST);
2914
1
  } else {
2915
1
    RETVAL_FALSE;
2916
1
  }
2917
2918
1
  zval_ptr_dtor_nogc(&default_value);
2919
1
}
2920
/* }}} */
2921
2922
/* {{{ Returns the default value's constant name if default value is constant or null */
2923
ZEND_METHOD(ReflectionParameter, getDefaultValueConstantName)
2924
0
{
2925
0
  const reflection_object *intern;
2926
0
  const parameter_reference *param;
2927
2928
0
  ZEND_PARSE_PARAMETERS_NONE();
2929
2930
0
  GET_REFLECTION_OBJECT_PTR(param);
2931
2932
0
  zval default_value;
2933
0
  if (get_parameter_default(&default_value, param) == FAILURE) {
2934
0
    zend_throw_exception_ex(reflection_exception_ptr, 0,
2935
0
      "Internal error: Failed to retrieve the default value");
2936
0
    RETURN_THROWS();
2937
0
  }
2938
2939
0
  if (Z_TYPE(default_value) != IS_CONSTANT_AST) {
2940
0
    zval_ptr_dtor_nogc(&default_value);
2941
0
    RETURN_NULL();
2942
0
  }
2943
2944
0
  zend_ast *ast = Z_ASTVAL(default_value);
2945
0
  if (ast->kind == ZEND_AST_CONSTANT) {
2946
0
    RETVAL_STR_COPY(zend_ast_get_constant_name(ast));
2947
0
  } else if (ast->kind == ZEND_AST_CONSTANT_CLASS) {
2948
0
    RETVAL_STRINGL("__CLASS__", sizeof("__CLASS__")-1);
2949
0
  } else if (ast->kind == ZEND_AST_CLASS_CONST) {
2950
0
    const zend_string *class_name = zend_ast_get_str(ast->child[0]);
2951
0
    const zend_string *const_name = zend_ast_get_str(ast->child[1]);
2952
0
    RETVAL_NEW_STR(zend_string_concat3(
2953
0
      ZSTR_VAL(class_name), ZSTR_LEN(class_name),
2954
0
      "::", sizeof("::")-1,
2955
0
      ZSTR_VAL(const_name), ZSTR_LEN(const_name)));
2956
0
  } else {
2957
0
    RETVAL_NULL();
2958
0
  }
2959
0
  zval_ptr_dtor_nogc(&default_value);
2960
0
}
2961
2962
/* {{{ Returns whether this parameter is a variadic parameter */
2963
ZEND_METHOD(ReflectionParameter, isVariadic)
2964
5
{
2965
5
  const reflection_object *intern;
2966
5
  const parameter_reference *param;
2967
2968
5
  ZEND_PARSE_PARAMETERS_NONE();
2969
5
  GET_REFLECTION_OBJECT_PTR(param);
2970
2971
5
  RETVAL_BOOL(ZEND_ARG_IS_VARIADIC(param->arg_info));
2972
5
}
2973
/* }}} */
2974
2975
/* {{{ Returns this constructor parameter has been promoted to a property */
2976
ZEND_METHOD(ReflectionParameter, isPromoted)
2977
0
{
2978
0
  const reflection_object *intern;
2979
0
  const parameter_reference *param;
2980
2981
0
  ZEND_PARSE_PARAMETERS_NONE();
2982
0
  GET_REFLECTION_OBJECT_PTR(param);
2983
2984
0
  RETVAL_BOOL(ZEND_ARG_IS_PROMOTED(param->arg_info));
2985
0
}
2986
/* }}} */
2987
2988
/* {{{ Returns whether the type MAY be null */
2989
ZEND_METHOD(ReflectionType, allowsNull)
2990
0
{
2991
0
  const reflection_object *intern;
2992
0
  const type_reference *param;
2993
2994
0
  ZEND_PARSE_PARAMETERS_NONE();
2995
0
  GET_REFLECTION_OBJECT_PTR(param);
2996
2997
0
  RETVAL_BOOL(ZEND_TYPE_ALLOW_NULL(param->type));
2998
0
}
2999
/* }}} */
3000
3001
/* For BC with iterable for named types */
3002
139
static zend_string *zend_named_reflection_type_to_string(zend_type type) {
3003
139
  if (ZEND_TYPE_IS_ITERABLE_FALLBACK(type)) {
3004
0
    if (ZEND_TYPE_FULL_MASK(type) & MAY_BE_NULL) {
3005
0
      return ZSTR_INIT_LITERAL("?iterable", false);
3006
0
    }
3007
0
    return ZSTR_KNOWN(ZEND_STR_ITERABLE);
3008
0
  }
3009
139
  return zend_type_to_string(type);
3010
139
}
3011
3012
/* {{{ Return the text of the type hint */
3013
ZEND_METHOD(ReflectionType, __toString)
3014
18
{
3015
18
  const reflection_object *intern;
3016
18
  const type_reference *param;
3017
3018
18
  ZEND_PARSE_PARAMETERS_NONE();
3019
18
  GET_REFLECTION_OBJECT_PTR(param);
3020
3021
18
  RETURN_STR(zend_named_reflection_type_to_string(param->type));
3022
18
}
3023
/* }}} */
3024
3025
/* {{{ Return the name of the type */
3026
ZEND_METHOD(ReflectionNamedType, getName)
3027
121
{
3028
121
  const reflection_object *intern;
3029
121
  const type_reference *param;
3030
3031
121
  ZEND_PARSE_PARAMETERS_NONE();
3032
121
  GET_REFLECTION_OBJECT_PTR(param);
3033
3034
  // Make a copy so that we don't modify the stored type information
3035
121
  zend_type type = param->type;
3036
121
  if (param->legacy_behavior) {
3037
116
    ZEND_TYPE_FULL_MASK(type) &= ~MAY_BE_NULL;
3038
116
  }
3039
121
  RETURN_STR(zend_named_reflection_type_to_string(type));
3040
121
}
3041
/* }}} */
3042
3043
/* {{{ Returns whether type is a builtin type */
3044
ZEND_METHOD(ReflectionNamedType, isBuiltin)
3045
55
{
3046
55
  const reflection_object *intern;
3047
55
  const type_reference *param;
3048
3049
55
  ZEND_PARSE_PARAMETERS_NONE();
3050
55
  GET_REFLECTION_OBJECT_PTR(param);
3051
3052
55
  if (ZEND_TYPE_IS_ITERABLE_FALLBACK(param->type)) {
3053
0
    RETURN_TRUE;
3054
0
  }
3055
3056
  /* Treat "static" as a class type for the purposes of reflection. */
3057
55
  RETVAL_BOOL(ZEND_TYPE_IS_ONLY_MASK(param->type)
3058
55
    && !(ZEND_TYPE_FULL_MASK(param->type) & MAY_BE_STATIC));
3059
55
}
3060
/* }}} */
3061
3062
0
static void append_type(zval *return_value, zend_type type) {
3063
  /* Drop iterable BC bit for type list */
3064
0
  if (ZEND_TYPE_IS_ITERABLE_FALLBACK(type)) {
3065
0
    ZEND_TYPE_FULL_MASK(type) &= ~_ZEND_TYPE_ITERABLE_BIT;
3066
0
  }
3067
3068
0
  zval reflection_type;
3069
0
  reflection_type_factory(type, &reflection_type, false);
3070
0
  zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &reflection_type);
3071
0
}
3072
3073
0
static void append_type_mask(zval *return_value, uint32_t type_mask) {
3074
0
  append_type(return_value, (zend_type) ZEND_TYPE_INIT_MASK(type_mask));
3075
0
}
3076
3077
/* {{{ Returns the types that are part of this union type */
3078
ZEND_METHOD(ReflectionUnionType, getTypes)
3079
0
{
3080
0
  const reflection_object *intern;
3081
0
  const type_reference *param;
3082
3083
0
  ZEND_PARSE_PARAMETERS_NONE();
3084
0
  GET_REFLECTION_OBJECT_PTR(param);
3085
3086
0
  array_init(return_value);
3087
0
  if (ZEND_TYPE_HAS_LIST(param->type)) {
3088
0
    const zend_type *list_type;
3089
0
    ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(param->type), list_type) {
3090
0
      append_type(return_value, *list_type);
3091
0
    } ZEND_TYPE_LIST_FOREACH_END();
3092
0
  } else if (ZEND_TYPE_HAS_NAME(param->type)) {
3093
0
    zend_string *name = ZEND_TYPE_NAME(param->type);
3094
0
    append_type(return_value, (zend_type) ZEND_TYPE_INIT_CLASS(name, false, 0));
3095
0
  }
3096
3097
0
  uint32_t type_mask = ZEND_TYPE_PURE_MASK(param->type);
3098
0
  ZEND_ASSERT(!(type_mask & MAY_BE_VOID));
3099
0
  ZEND_ASSERT(!(type_mask & MAY_BE_NEVER));
3100
0
  if (type_mask & MAY_BE_STATIC) {
3101
0
    append_type_mask(return_value, MAY_BE_STATIC);
3102
0
  }
3103
0
  if (type_mask & MAY_BE_CALLABLE) {
3104
0
    append_type_mask(return_value, MAY_BE_CALLABLE);
3105
0
  }
3106
0
  if (type_mask & MAY_BE_OBJECT) {
3107
0
    append_type_mask(return_value, MAY_BE_OBJECT);
3108
0
  }
3109
0
  if (type_mask & MAY_BE_ARRAY) {
3110
0
    append_type_mask(return_value, MAY_BE_ARRAY);
3111
0
  }
3112
0
  if (type_mask & MAY_BE_STRING) {
3113
0
    append_type_mask(return_value, MAY_BE_STRING);
3114
0
  }
3115
0
  if (type_mask & MAY_BE_LONG) {
3116
0
    append_type_mask(return_value, MAY_BE_LONG);
3117
0
  }
3118
0
  if (type_mask & MAY_BE_DOUBLE) {
3119
0
    append_type_mask(return_value, MAY_BE_DOUBLE);
3120
0
  }
3121
0
  if ((type_mask & MAY_BE_BOOL) == MAY_BE_BOOL) {
3122
0
    append_type_mask(return_value, MAY_BE_BOOL);
3123
0
  } else if (type_mask & MAY_BE_TRUE) {
3124
0
    append_type_mask(return_value, MAY_BE_TRUE);
3125
0
  } else if (type_mask & MAY_BE_FALSE) {
3126
0
    append_type_mask(return_value, MAY_BE_FALSE);
3127
0
  }
3128
0
  if (type_mask & MAY_BE_NULL) {
3129
0
    append_type_mask(return_value, MAY_BE_NULL);
3130
0
  }
3131
0
}
3132
/* }}} */
3133
3134
/* {{{ Returns the types that are part of this intersection type */
3135
ZEND_METHOD(ReflectionIntersectionType, getTypes)
3136
0
{
3137
0
  const reflection_object *intern;
3138
0
  const type_reference *param;
3139
3140
0
  ZEND_PARSE_PARAMETERS_NONE();
3141
0
  GET_REFLECTION_OBJECT_PTR(param);
3142
3143
0
  ZEND_ASSERT(ZEND_TYPE_HAS_LIST(param->type));
3144
3145
0
  array_init(return_value);
3146
0
  ZEND_TYPE_LIST_FOREACH(ZEND_TYPE_LIST(param->type), const zend_type *list_type) {
3147
0
    append_type(return_value, *list_type);
3148
0
  } ZEND_TYPE_LIST_FOREACH_END();
3149
0
}
3150
/* }}} */
3151
3152
/* {{{ Constructor. Throws an Exception in case the given method does not exist */
3153
static void instantiate_reflection_method(INTERNAL_FUNCTION_PARAMETERS, bool is_constructor)
3154
278
{
3155
278
  zend_object *arg1_obj = NULL;
3156
278
  zend_string *arg1_str;
3157
278
  zend_string *arg2_str = NULL;
3158
3159
278
  zend_object *orig_obj = NULL;
3160
278
  zend_class_entry *ce = NULL;
3161
278
  zend_string *class_name = NULL;
3162
278
  const char *method_name;
3163
278
  size_t method_name_len;
3164
3165
278
  if (is_constructor) {
3166
268
    if (ZEND_NUM_ARGS() == 1) {
3167
8
      zend_error(E_DEPRECATED, "Calling ReflectionMethod::__construct() with 1 argument is deprecated, "
3168
8
        "use ReflectionMethod::createFromMethodName() instead");
3169
8
      if (UNEXPECTED(EG(exception))) {
3170
0
        RETURN_THROWS();
3171
0
      }
3172
8
    }
3173
3174
798
    ZEND_PARSE_PARAMETERS_START(1, 2)
3175
1.31k
      Z_PARAM_OBJ_OR_STR(arg1_obj, arg1_str)
3176
1.31k
      Z_PARAM_OPTIONAL
3177
1.31k
      Z_PARAM_STR_OR_NULL(arg2_str)
3178
268
    ZEND_PARSE_PARAMETERS_END();
3179
268
  } else {
3180
30
    ZEND_PARSE_PARAMETERS_START(1, 1)
3181
40
      Z_PARAM_STR(arg1_str)
3182
10
    ZEND_PARSE_PARAMETERS_END();
3183
10
  }
3184
3185
272
  if (arg1_obj) {
3186
42
    if (!arg2_str) {
3187
0
      zend_argument_value_error(2, "cannot be null when argument #1 ($objectOrMethod) is an object");
3188
0
      RETURN_THROWS();
3189
0
    }
3190
3191
42
    orig_obj = arg1_obj;
3192
42
    ce = arg1_obj->ce;
3193
42
    method_name = ZSTR_VAL(arg2_str);
3194
42
    method_name_len = ZSTR_LEN(arg2_str);
3195
230
  } else if (arg2_str) {
3196
208
    class_name = zend_string_copy(arg1_str);
3197
208
    method_name = ZSTR_VAL(arg2_str);
3198
208
    method_name_len = ZSTR_LEN(arg2_str);
3199
208
  } else {
3200
22
    const char *tmp;
3201
22
    const char *name = ZSTR_VAL(arg1_str);
3202
3203
22
    if ((tmp = zend_memnstr(name, "::", 2, name + ZSTR_LEN(arg1_str))) == NULL) {
3204
13
      zend_argument_error(reflection_exception_ptr, 1, "must be a valid method name");
3205
13
      RETURN_THROWS();
3206
13
    }
3207
9
    size_t tmp_len = tmp - name;
3208
3209
9
    class_name = zend_string_init(name, tmp_len, false);
3210
9
    method_name = tmp + 2;
3211
9
    method_name_len = ZSTR_LEN(arg1_str) - tmp_len - 2;
3212
9
  }
3213
3214
259
  if (class_name) {
3215
217
    if ((ce = zend_lookup_class(class_name)) == NULL) {
3216
7
      if (!EG(exception)) {
3217
6
        zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%pS\" does not exist", class_name);
3218
6
      }
3219
7
      zend_string_release(class_name);
3220
7
      RETURN_THROWS();
3221
7
    }
3222
3223
210
    zend_string_release(class_name);
3224
210
  }
3225
3226
252
  zval *object;
3227
252
  if (is_constructor) {
3228
243
    object = ZEND_THIS;
3229
243
  } else {
3230
9
    zend_class_entry *called_ce = execute_data->This.value.ce ? execute_data->This.value.ce : reflection_method_ptr;
3231
9
    if (UNEXPECTED(object_init_ex(return_value, called_ce) != SUCCESS)) {
3232
1
      RETURN_THROWS();
3233
1
    }
3234
8
    object = return_value;
3235
8
  }
3236
251
  reflection_object *intern = Z_REFLECTION_P(object);
3237
3238
251
  char *lcname = zend_str_tolower_dup(method_name, method_name_len);
3239
3240
251
  zend_function *mptr;
3241
251
  if (ce == zend_ce_closure && orig_obj && (method_name_len == sizeof(ZEND_INVOKE_FUNC_NAME)-1)
3242
35
    && memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
3243
29
    && (mptr = zend_get_closure_invoke_method(orig_obj)) != NULL)
3244
29
  {
3245
    /* Store the original closure object so we can validate it in invoke/invokeArgs.
3246
     * Each closure has a unique __invoke signature, so we must reject different closures. */
3247
29
    zval_ptr_dtor(&intern->obj);
3248
29
    ZVAL_OBJ_COPY(&intern->obj, orig_obj);
3249
222
  } else if ((mptr = zend_hash_str_find_ptr(&ce->function_table, lcname, method_name_len)) == NULL) {
3250
21
    efree(lcname);
3251
21
    ALLOCA_FLAG(use_heap);
3252
21
    zend_string *method_name_zstr;
3253
21
    ZSTR_ALLOCA_INIT(method_name_zstr, method_name, method_name_len, use_heap);
3254
21
    zend_throw_exception_ex(reflection_exception_ptr, 0,
3255
21
      "Method %pS::%pS() does not exist", ce->name, method_name_zstr);
3256
21
    ZSTR_ALLOCA_FREE(method_name_zstr, use_heap);
3257
3258
21
    RETURN_THROWS();
3259
201
  } else {
3260
201
    zval_ptr_dtor(&intern->obj);
3261
201
    ZVAL_UNDEF(&intern->obj);
3262
201
  }
3263
230
  efree(lcname);
3264
3265
230
  if (intern->ptr) {
3266
0
    ZEND_ASSERT(is_constructor);
3267
0
    _free_function(intern->ptr);
3268
0
    zval_ptr_dtor(reflection_prop_name(object));
3269
0
    zval_ptr_dtor(reflection_prop_class(object));
3270
0
  }
3271
3272
230
  ZVAL_STR_COPY(reflection_prop_name(object), mptr->common.function_name);
3273
230
  ZVAL_STR_COPY(reflection_prop_class(object), mptr->common.scope->name);
3274
230
  intern->ptr = mptr;
3275
230
  intern->ref_type = REF_TYPE_FUNCTION;
3276
230
  intern->ce = ce;
3277
230
}
3278
3279
/* {{{ Constructor. Throws an Exception in case the given method does not exist */
3280
268
ZEND_METHOD(ReflectionMethod, __construct) {
3281
268
  instantiate_reflection_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
3282
268
}
3283
/* }}} */
3284
3285
10
ZEND_METHOD(ReflectionMethod, createFromMethodName) {
3286
10
  instantiate_reflection_method(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
3287
10
}
3288
3289
/* {{{ Returns a string representation */
3290
ZEND_METHOD(ReflectionMethod, __toString)
3291
142
{
3292
142
  const reflection_object *intern;
3293
142
  const zend_function *mptr;
3294
142
  smart_str str = {0};
3295
3296
142
  ZEND_PARSE_PARAMETERS_NONE();
3297
142
  GET_REFLECTION_OBJECT_PTR(mptr);
3298
142
  _function_string(&str, mptr, intern->ce, "");
3299
142
  RETURN_STR(smart_str_extract(&str));
3300
142
}
3301
/* }}} */
3302
3303
/* {{{ Returns a dynamically created closure for the function */
3304
ZEND_METHOD(ReflectionMethod, getClosure)
3305
26
{
3306
26
  reflection_object *intern;
3307
26
  zval *obj = NULL;
3308
26
  zend_function *mptr;
3309
3310
26
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "|o!", &obj) == FAILURE) {
3311
0
    RETURN_THROWS();
3312
0
  }
3313
3314
26
  GET_REFLECTION_OBJECT_PTR(mptr);
3315
3316
26
  if (mptr->common.fn_flags & ZEND_ACC_STATIC) {
3317
0
    zend_create_fake_closure(return_value, mptr, mptr->common.scope, mptr->common.scope, NULL);
3318
0
    return;
3319
0
  }
3320
26
  if (!obj) {
3321
0
    zend_argument_value_error(1, "cannot be null for non-static methods");
3322
0
    RETURN_THROWS();
3323
0
  }
3324
3325
26
  if (!instanceof_function(Z_OBJCE_P(obj), mptr->common.scope)) {
3326
0
    zend_throw_exception(reflection_exception_ptr, "Given object is not an instance of the class this method was declared in", 0);
3327
0
    RETURN_THROWS();
3328
0
  }
3329
3330
  /* This is an original closure object and __invoke is to be called. */
3331
26
  if (Z_OBJCE_P(obj) == zend_ce_closure &&
3332
0
    (mptr->internal_function.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE))
3333
0
  {
3334
0
    RETURN_OBJ_COPY(Z_OBJ_P(obj));
3335
0
  }
3336
26
  zend_create_fake_closure(return_value, mptr, mptr->common.scope, Z_OBJCE_P(obj), Z_OBJ_P(obj));
3337
26
}
3338
/* }}} */
3339
3340
/* {{{ reflection_method_invoke */
3341
static void reflection_method_invoke(INTERNAL_FUNCTION_PARAMETERS, bool variadic)
3342
97
{
3343
97
  zval *params = NULL, *object;
3344
97
  HashTable *named_params = NULL;
3345
97
  reflection_object *intern;
3346
97
  zend_function *mptr;
3347
97
  uint32_t argc = 0;
3348
97
  const zend_class_entry *obj_ce;
3349
3350
97
  GET_REFLECTION_OBJECT_PTR(mptr);
3351
3352
97
  if (mptr->common.fn_flags & ZEND_ACC_ABSTRACT) {
3353
1
    zend_throw_exception_ex(reflection_exception_ptr, 0,
3354
1
      "Trying to invoke abstract method %pS::%pS()",
3355
1
      mptr->common.scope->name, mptr->common.function_name);
3356
1
    RETURN_THROWS();
3357
1
  }
3358
3359
96
  if (variadic) {
3360
228
    ZEND_PARSE_PARAMETERS_START(1, -1)
3361
304
      Z_PARAM_OBJECT_OR_NULL(object)
3362
76
      Z_PARAM_VARIADIC_WITH_NAMED(params, argc, named_params)
3363
76
    ZEND_PARSE_PARAMETERS_END();
3364
76
  } else {
3365
20
    if (zend_parse_parameters(ZEND_NUM_ARGS(), "o!h", &object, &named_params) == FAILURE) {
3366
0
      RETURN_THROWS();
3367
0
    }
3368
20
  }
3369
3370
  /* In case this is a static method, we shouldn't pass an object_ptr
3371
   * (which is used as calling context aka $this). We can thus ignore the
3372
   * first parameter.
3373
   *
3374
   * Else, we verify that the given object is an instance of the class.
3375
   */
3376
96
  if (mptr->common.fn_flags & ZEND_ACC_STATIC) {
3377
0
    if (object) {
3378
0
      zend_string *method_name = get_active_function_or_method_name();
3379
0
      zend_error(
3380
0
        E_DEPRECATED,
3381
0
        "Calling %pS() for static method %pS::%pS() does not need an object parameter",
3382
0
        method_name,
3383
0
        mptr->common.scope->name,
3384
0
        mptr->common.function_name
3385
0
      );
3386
0
      zend_string_release(method_name);
3387
0
      if (UNEXPECTED(EG(exception))) {
3388
0
        RETURN_THROWS();
3389
0
      }
3390
0
      object = NULL;
3391
0
    } 
3392
0
    obj_ce = mptr->common.scope;
3393
96
  } else {
3394
96
    if (!object) {
3395
2
      zend_throw_exception_ex(reflection_exception_ptr, 0,
3396
2
        "Trying to invoke non static method %pS::%pS() without an object",
3397
2
        mptr->common.scope->name, mptr->common.function_name);
3398
2
      RETURN_THROWS();
3399
2
    }
3400
3401
94
    obj_ce = Z_OBJCE_P(object);
3402
3403
94
    if (!instanceof_function(obj_ce, mptr->common.scope)) {
3404
0
      if (!variadic) {
3405
0
        efree(params);
3406
0
      }
3407
0
      zend_throw_exception(reflection_exception_ptr, "Given object is not an instance of the class this method was declared in", 0);
3408
0
      RETURN_THROWS();
3409
0
    }
3410
3411
    /* For Closure::__invoke(), closures from different source locations have
3412
     * different signatures, so we must reject those. */
3413
94
    if (obj_ce == zend_ce_closure && !Z_ISUNDEF(intern->obj)
3414
0
        && Z_OBJ_P(object) != Z_OBJ(intern->obj)) {
3415
0
      const zend_function *orig_func = zend_get_closure_method_def(Z_OBJ(intern->obj));
3416
0
      const zend_function *given_func = zend_get_closure_method_def(Z_OBJ_P(object));
3417
3418
0
      bool same_closure = false;
3419
      /* Check if they are either both fake closures or they both are not. */
3420
0
      if ((orig_func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) == (given_func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE)) {
3421
0
        if (orig_func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE) {
3422
          /* For fake closures, scope and name must match. */
3423
0
          same_closure = orig_func->common.scope == given_func->common.scope
3424
0
            && orig_func->common.function_name == given_func->common.function_name;
3425
0
        } else {
3426
          /* Otherwise the opcode structure must be identical. */
3427
0
          ZEND_ASSERT(orig_func->type == ZEND_USER_FUNCTION);
3428
0
          same_closure = orig_func->op_array.opcodes == given_func->op_array.opcodes;
3429
0
        }
3430
0
      }
3431
3432
0
      if (!same_closure) {
3433
0
        if (!variadic) {
3434
0
          efree(params);
3435
0
        }
3436
0
        zend_throw_exception(reflection_exception_ptr, "Given Closure is not the same as the reflected Closure", 0);
3437
0
        RETURN_THROWS();
3438
0
      }
3439
0
    }
3440
94
  }
3441
  /* Copy the zend_function when calling via handler (e.g. Closure::__invoke()) */
3442
94
  zend_function *callback = _copy_function(mptr);
3443
94
  zval retval;
3444
94
  zend_call_known_function(callback, (object ? Z_OBJ_P(object) : NULL), intern->ce, &retval, argc, params, named_params);
3445
3446
94
  if (Z_ISREF(retval)) {
3447
10
    zend_unwrap_reference(&retval);
3448
10
  }
3449
94
  RETURN_COPY_VALUE(&retval);
3450
94
}
3451
/* }}} */
3452
3453
/* {{{ Invokes the method. */
3454
ZEND_METHOD(ReflectionMethod, invoke)
3455
77
{
3456
77
  reflection_method_invoke(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
3457
77
}
3458
/* }}} */
3459
3460
/* {{{ Invokes the function and pass its arguments as array. */
3461
ZEND_METHOD(ReflectionMethod, invokeArgs)
3462
20
{
3463
20
  reflection_method_invoke(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
3464
20
}
3465
/* }}} */
3466
3467
/* {{{ Returns whether this method is final */
3468
ZEND_METHOD(ReflectionMethod, isFinal)
3469
54
{
3470
54
  _function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_FINAL);
3471
54
}
3472
/* }}} */
3473
3474
/* {{{ Returns whether this method is abstract */
3475
ZEND_METHOD(ReflectionMethod, isAbstract)
3476
1
{
3477
1
  _function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_ABSTRACT);
3478
1
}
3479
/* }}} */
3480
3481
/* {{{ Returns whether this method is public */
3482
ZEND_METHOD(ReflectionMethod, isPublic)
3483
54
{
3484
54
  _function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PUBLIC);
3485
54
}
3486
/* }}} */
3487
3488
/* {{{ Returns whether this method is private */
3489
ZEND_METHOD(ReflectionMethod, isPrivate)
3490
54
{
3491
54
  _function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PRIVATE);
3492
54
}
3493
/* }}} */
3494
3495
/* {{{ Returns whether this method is protected */
3496
ZEND_METHOD(ReflectionMethod, isProtected)
3497
54
{
3498
54
  _function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PROTECTED);
3499
54
}
3500
/* }}} */
3501
3502
/* {{{ Returns whether this function is deprecated */
3503
ZEND_METHOD(ReflectionFunctionAbstract, isDeprecated)
3504
9
{
3505
9
  _function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_DEPRECATED);
3506
9
}
3507
/* }}} */
3508
3509
/* {{{ Returns whether this function is a generator */
3510
ZEND_METHOD(ReflectionFunctionAbstract, isGenerator)
3511
0
{
3512
0
  _function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_GENERATOR);
3513
0
}
3514
/* }}} */
3515
3516
/* {{{ Returns whether this function is variadic */
3517
ZEND_METHOD(ReflectionFunctionAbstract, isVariadic)
3518
5
{
3519
5
  _function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_VARIADIC);
3520
5
}
3521
/* }}} */
3522
3523
/* {{{ Returns whether this function is static */
3524
ZEND_METHOD(ReflectionFunctionAbstract, isStatic)
3525
0
{
3526
0
  _function_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_STATIC);
3527
0
}
3528
/* }}} */
3529
3530
/* {{{ Returns whether this function is defined in namespace */
3531
ZEND_METHOD(ReflectionFunctionAbstract, inNamespace)
3532
56
{
3533
56
  const reflection_object *intern;
3534
56
  const zend_function *fptr;
3535
3536
56
  ZEND_PARSE_PARAMETERS_NONE();
3537
3538
56
  GET_REFLECTION_OBJECT_PTR(fptr);
3539
3540
56
  if ((fptr->common.fn_flags & (ZEND_ACC_CLOSURE | ZEND_ACC_FAKE_CLOSURE)) == ZEND_ACC_CLOSURE) {
3541
24
    RETURN_FALSE;
3542
24
  }
3543
3544
32
  const zend_string *name = fptr->common.function_name;
3545
32
  const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
3546
32
  RETURN_BOOL(backslash);
3547
32
}
3548
/* }}} */
3549
3550
/* {{{ Returns the name of namespace where this function is defined */
3551
ZEND_METHOD(ReflectionFunctionAbstract, getNamespaceName)
3552
57
{
3553
57
  const reflection_object *intern;
3554
57
  const zend_function *fptr;
3555
3556
57
  ZEND_PARSE_PARAMETERS_NONE();
3557
3558
57
  GET_REFLECTION_OBJECT_PTR(fptr);
3559
3560
57
  if ((fptr->common.fn_flags & (ZEND_ACC_CLOSURE | ZEND_ACC_FAKE_CLOSURE)) == ZEND_ACC_CLOSURE) {
3561
27
    RETURN_EMPTY_STRING();
3562
27
  }
3563
3564
30
  const zend_string *name = fptr->common.function_name;
3565
30
  const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
3566
30
  if (backslash) {
3567
30
    RETURN_STRINGL(ZSTR_VAL(name), backslash - ZSTR_VAL(name));
3568
30
  }
3569
0
  RETURN_EMPTY_STRING();
3570
0
}
3571
/* }}} */
3572
3573
/* {{{ Returns the short name of the function (without namespace part) */
3574
ZEND_METHOD(ReflectionFunctionAbstract, getShortName)
3575
55
{
3576
55
  const reflection_object *intern;
3577
55
  const zend_function *fptr;
3578
3579
55
  ZEND_PARSE_PARAMETERS_NONE();
3580
3581
55
  GET_REFLECTION_OBJECT_PTR(fptr);
3582
3583
55
  zend_string *name = fptr->common.function_name;
3584
55
  if ((fptr->common.fn_flags & (ZEND_ACC_CLOSURE | ZEND_ACC_FAKE_CLOSURE)) != ZEND_ACC_CLOSURE) {
3585
34
    const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
3586
34
    if (backslash) {
3587
33
      RETURN_STRINGL(backslash + 1, ZSTR_LEN(name) - (backslash - ZSTR_VAL(name) + 1));
3588
33
    }
3589
34
  }
3590
3591
22
  RETURN_STR_COPY(name);
3592
22
}
3593
/* }}} */
3594
3595
/* {{{ Return whether the function has a return type */
3596
ZEND_METHOD(ReflectionFunctionAbstract, hasReturnType)
3597
0
{
3598
0
  const reflection_object *intern;
3599
0
  const zend_function *fptr;
3600
3601
0
  ZEND_PARSE_PARAMETERS_NONE();
3602
3603
0
  GET_REFLECTION_OBJECT_PTR(fptr);
3604
3605
0
  RETVAL_BOOL((fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) && !ZEND_ARG_TYPE_IS_TENTATIVE(&fptr->common.arg_info[-1]));
3606
0
}
3607
/* }}} */
3608
3609
/* {{{ Returns the return type associated with the function */
3610
ZEND_METHOD(ReflectionFunctionAbstract, getReturnType)
3611
49
{
3612
49
  const reflection_object *intern;
3613
49
  const zend_function *fptr;
3614
3615
49
  ZEND_PARSE_PARAMETERS_NONE();
3616
3617
49
  GET_REFLECTION_OBJECT_PTR(fptr);
3618
3619
49
  if (!(fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || ZEND_ARG_TYPE_IS_TENTATIVE(&fptr->common.arg_info[-1])) {
3620
0
    RETURN_NULL();
3621
0
  }
3622
3623
49
  reflection_type_factory(fptr->common.arg_info[-1].type, return_value, true);
3624
49
}
3625
/* }}} */
3626
3627
/* {{{ Return whether the function has a tentative return type */
3628
ZEND_METHOD(ReflectionFunctionAbstract, hasTentativeReturnType)
3629
0
{
3630
0
  const reflection_object *intern;
3631
0
  const zend_function *fptr;
3632
3633
0
  ZEND_PARSE_PARAMETERS_NONE();
3634
3635
0
  GET_REFLECTION_OBJECT_PTR(fptr);
3636
3637
0
  RETVAL_BOOL(fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE && ZEND_ARG_TYPE_IS_TENTATIVE(&fptr->common.arg_info[-1]));
3638
0
}
3639
/* }}} */
3640
3641
/* {{{ Returns the tentative return type associated with the function */
3642
ZEND_METHOD(ReflectionFunctionAbstract, getTentativeReturnType)
3643
0
{
3644
0
  const reflection_object *intern;
3645
0
  const zend_function *fptr;
3646
3647
0
  ZEND_PARSE_PARAMETERS_NONE();
3648
3649
0
  GET_REFLECTION_OBJECT_PTR(fptr);
3650
3651
0
  if (!(fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) || !ZEND_ARG_TYPE_IS_TENTATIVE(&fptr->common.arg_info[-1])) {
3652
0
    RETURN_NULL();
3653
0
  }
3654
3655
0
  reflection_type_factory(fptr->common.arg_info[-1].type, return_value, true);
3656
0
}
3657
/* }}} */
3658
3659
/* {{{ Returns whether this method is the constructor */
3660
ZEND_METHOD(ReflectionMethod, isConstructor)
3661
1
{
3662
1
  const reflection_object *intern;
3663
1
  const zend_function *mptr;
3664
3665
1
  ZEND_PARSE_PARAMETERS_NONE();
3666
1
  GET_REFLECTION_OBJECT_PTR(mptr);
3667
  /* we need to check if the ctor is the ctor of the class level we are
3668
   * looking at since we might be looking at an inherited old style ctor
3669
   * defined in base class. */
3670
1
  RETURN_BOOL((mptr->common.fn_flags & ZEND_ACC_CTOR) && intern->ce->constructor && intern->ce->constructor->common.scope == mptr->common.scope);
3671
1
}
3672
/* }}} */
3673
3674
/* {{{ Returns whether this method is a destructor */
3675
ZEND_METHOD(ReflectionMethod, isDestructor)
3676
0
{
3677
0
  const reflection_object *intern;
3678
0
  const zend_function *mptr;
3679
3680
0
  ZEND_PARSE_PARAMETERS_NONE();
3681
0
  GET_REFLECTION_OBJECT_PTR(mptr);
3682
0
  RETURN_BOOL(zend_string_equals_literal_ci(
3683
0
    mptr->common.function_name, ZEND_DESTRUCTOR_FUNC_NAME));
3684
0
}
3685
/* }}} */
3686
3687
/* {{{ Returns a bitfield of the modifiers for this method */
3688
ZEND_METHOD(ReflectionMethod, getModifiers)
3689
0
{
3690
0
  const reflection_object *intern;
3691
0
  const zend_function *mptr;
3692
0
  uint32_t keep_flags = ZEND_ACC_PPP_MASK
3693
0
    | ZEND_ACC_STATIC | ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL;
3694
3695
0
  ZEND_PARSE_PARAMETERS_NONE();
3696
0
  GET_REFLECTION_OBJECT_PTR(mptr);
3697
3698
0
  RETURN_LONG((mptr->common.fn_flags & keep_flags));
3699
0
}
3700
/* }}} */
3701
3702
/* {{{ Get the declaring class */
3703
ZEND_METHOD(ReflectionMethod, getDeclaringClass)
3704
6
{
3705
6
  const reflection_object *intern;
3706
6
  const zend_function *mptr;
3707
3708
6
  ZEND_PARSE_PARAMETERS_NONE();
3709
3710
6
  GET_REFLECTION_OBJECT_PTR(mptr);
3711
3712
6
  zend_reflection_class_factory(mptr->common.scope, return_value);
3713
6
}
3714
/* }}} */
3715
3716
/* {{{ Returns whether a method has a prototype or not */
3717
ZEND_METHOD(ReflectionMethod, hasPrototype)
3718
0
{
3719
0
  const reflection_object *intern;
3720
0
  const zend_function *mptr;
3721
3722
0
  ZEND_PARSE_PARAMETERS_NONE();
3723
3724
0
  GET_REFLECTION_OBJECT_PTR(mptr);
3725
0
  RETURN_BOOL(mptr->common.prototype != NULL);
3726
0
}
3727
/* }}} */
3728
3729
/* {{{ Get the prototype */
3730
ZEND_METHOD(ReflectionMethod, getPrototype)
3731
2
{
3732
2
  const reflection_object *intern;
3733
2
  const zend_function *mptr;
3734
3735
2
  ZEND_PARSE_PARAMETERS_NONE();
3736
3737
2
  GET_REFLECTION_OBJECT_PTR(mptr);
3738
3739
2
  if (!mptr->common.prototype) {
3740
1
    zend_throw_exception_ex(reflection_exception_ptr, 0,
3741
1
      "Method %pS::%pS() does not have a prototype", intern->ce->name, mptr->common.function_name);
3742
1
    RETURN_THROWS();
3743
1
  }
3744
3745
1
  reflection_method_factory(mptr->common.prototype->common.scope, mptr->common.prototype, NULL, return_value);
3746
1
}
3747
/* }}} */
3748
3749
/* {{{ Sets whether non-public methods can be invoked */
3750
ZEND_METHOD(ReflectionMethod, setAccessible)
3751
0
{
3752
0
  bool visible;
3753
3754
0
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "b", &visible) == FAILURE) {
3755
0
    RETURN_THROWS();
3756
0
  }
3757
0
}
3758
/* }}} */
3759
3760
/* {{{ Constructor. Throws an Exception in case the given class constant does not exist */
3761
ZEND_METHOD(ReflectionClassConstant, __construct)
3762
117
{
3763
117
  zend_string *classname_str;
3764
117
  zend_object *classname_obj;
3765
117
  zend_string *constname;
3766
117
  zend_class_constant *constant = NULL;
3767
3768
339
  ZEND_PARSE_PARAMETERS_START(2, 2)
3769
525
    Z_PARAM_OBJ_OR_STR(classname_obj, classname_str)
3770
525
    Z_PARAM_STR(constname)
3771
117
  ZEND_PARSE_PARAMETERS_END();
3772
3773
105
  zend_class_entry *ce;
3774
105
  if (classname_obj) {
3775
0
    ce = classname_obj->ce;
3776
105
  } else if ((ce = zend_lookup_class(classname_str)) == NULL) {
3777
3
    zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%pS\" does not exist", classname_str);
3778
3
    RETURN_THROWS();
3779
3
  }
3780
3781
102
  zval *object = ZEND_THIS;
3782
102
  reflection_object *intern = Z_REFLECTION_P(object);
3783
3784
102
  if ((constant = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), constname)) == NULL) {
3785
7
    zend_throw_exception_ex(reflection_exception_ptr, 0, "Constant %pS::%pS does not exist", ce->name, constname);
3786
7
    RETURN_THROWS();
3787
7
  }
3788
3789
95
  if (intern->ptr) {
3790
0
    zval_ptr_dtor(reflection_prop_name(object));
3791
0
    zval_ptr_dtor(reflection_prop_class(object));
3792
0
  }
3793
3794
95
  intern->ptr = constant;
3795
95
  intern->ref_type = REF_TYPE_CLASS_CONSTANT;
3796
95
  intern->ce = constant->ce;
3797
95
  ZVAL_STR_COPY(reflection_prop_name(object), constname);
3798
95
  ZVAL_STR_COPY(reflection_prop_class(object), constant->ce->name);
3799
95
}
3800
/* }}} */
3801
3802
/* {{{ Returns a string representation */
3803
ZEND_METHOD(ReflectionClassConstant, __toString)
3804
13
{
3805
13
  const reflection_object *intern;
3806
13
  zend_class_constant *ref;
3807
13
  smart_str str = {0};
3808
3809
13
  ZEND_PARSE_PARAMETERS_NONE();
3810
3811
13
  GET_REFLECTION_OBJECT_PTR(ref);
3812
3813
13
  zval *name = reflection_prop_name(ZEND_THIS);
3814
13
  if (Z_ISUNDEF_P(name)) {
3815
0
    zend_throw_error(NULL,
3816
0
      "Typed property ReflectionClassConstant::$name "
3817
0
      "must not be accessed before initialization");
3818
0
    RETURN_THROWS();
3819
0
  }
3820
13
  ZVAL_DEREF(name);
3821
13
  ZEND_ASSERT(Z_TYPE_P(name) == IS_STRING);
3822
3823
13
  _class_const_string(&str, Z_STR_P(name), ref, "");
3824
13
  RETURN_STR(smart_str_extract(&str));
3825
13
}
3826
/* }}} */
3827
3828
/* {{{ Returns the constant' name */
3829
ZEND_METHOD(ReflectionClassConstant, getName)
3830
0
{
3831
0
  ZEND_PARSE_PARAMETERS_NONE();
3832
3833
0
  zval *name = reflection_prop_name(ZEND_THIS);
3834
0
  if (Z_ISUNDEF_P(name)) {
3835
0
    zend_throw_error(NULL,
3836
0
      "Typed property ReflectionClassConstant::$name "
3837
0
      "must not be accessed before initialization");
3838
0
    RETURN_THROWS();
3839
0
  }
3840
3841
0
  RETURN_COPY_DEREF(name);
3842
0
}
3843
/* }}} */
3844
3845
/* Returns the type associated with the class constant */
3846
ZEND_METHOD(ReflectionClassConstant, getType)
3847
0
{
3848
0
  const reflection_object *intern;
3849
0
  const zend_class_constant *ref;
3850
3851
0
  ZEND_PARSE_PARAMETERS_NONE();
3852
3853
0
  GET_REFLECTION_OBJECT_PTR(ref);
3854
3855
0
  if (!ZEND_TYPE_IS_SET(ref->type)) {
3856
0
    RETURN_NULL();
3857
0
  }
3858
3859
0
  reflection_type_factory(ref->type, return_value, true);
3860
0
}
3861
3862
/* Returns whether class constant has a type */
3863
ZEND_METHOD(ReflectionClassConstant, hasType)
3864
0
{
3865
0
  const reflection_object *intern;
3866
0
  const zend_class_constant *ref;
3867
3868
0
  ZEND_PARSE_PARAMETERS_NONE();
3869
3870
0
  GET_REFLECTION_OBJECT_PTR(ref);
3871
0
  RETVAL_BOOL(ZEND_TYPE_IS_SET(ref->type));
3872
0
}
3873
3874
static void _class_constant_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask) /* {{{ */
3875
7
{
3876
7
  const reflection_object *intern;
3877
7
  const zend_class_constant *ref;
3878
3879
7
  ZEND_PARSE_PARAMETERS_NONE();
3880
7
  GET_REFLECTION_OBJECT_PTR(ref);
3881
7
  RETURN_BOOL(ZEND_CLASS_CONST_FLAGS(ref) & mask);
3882
7
}
3883
/* }}} */
3884
3885
/* {{{ Returns whether this constant is public */
3886
ZEND_METHOD(ReflectionClassConstant, isPublic)
3887
0
{
3888
0
  _class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PUBLIC);
3889
0
}
3890
/* }}} */
3891
3892
/* {{{ Returns whether this constant is private */
3893
ZEND_METHOD(ReflectionClassConstant, isPrivate)
3894
0
{
3895
0
  _class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PRIVATE);
3896
0
}
3897
/* }}} */
3898
3899
/* {{{ Returns whether this constant is protected */
3900
ZEND_METHOD(ReflectionClassConstant, isProtected)
3901
0
{
3902
0
  _class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PROTECTED);
3903
0
}
3904
/* }}} */
3905
3906
/* Returns whether this constant is final */
3907
ZEND_METHOD(ReflectionClassConstant, isFinal)
3908
0
{
3909
0
  _class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_FINAL);
3910
0
}
3911
3912
/* {{{ Returns a bitfield of the modifiers for this constant */
3913
ZEND_METHOD(ReflectionClassConstant, getModifiers)
3914
0
{
3915
0
  const reflection_object *intern;
3916
0
  const zend_class_constant *ref;
3917
0
  uint32_t keep_flags = ZEND_ACC_FINAL | ZEND_ACC_PPP_MASK;
3918
3919
0
  ZEND_PARSE_PARAMETERS_NONE();
3920
0
  GET_REFLECTION_OBJECT_PTR(ref);
3921
3922
0
  RETURN_LONG(ZEND_CLASS_CONST_FLAGS(ref) & keep_flags);
3923
0
}
3924
/* }}} */
3925
3926
/* {{{ Returns this constant's value */
3927
ZEND_METHOD(ReflectionClassConstant, getValue)
3928
0
{
3929
0
  const reflection_object *intern;
3930
0
  zend_class_constant *ref;
3931
3932
0
  ZEND_PARSE_PARAMETERS_NONE();
3933
3934
0
  GET_REFLECTION_OBJECT_PTR(ref);
3935
3936
0
  const zval *name = reflection_prop_name(ZEND_THIS);
3937
0
  if (Z_ISUNDEF_P(name)) {
3938
0
    zend_throw_error(NULL,
3939
0
      "Typed property ReflectionClassConstant::$name "
3940
0
      "must not be accessed before initialization");
3941
0
    RETURN_THROWS();
3942
0
  }
3943
3944
0
  if (Z_TYPE(ref->value) == IS_CONSTANT_AST) {
3945
0
    zend_result result = zend_update_class_constant(ref, Z_STR_P(name), ref->ce);
3946
0
    if (result == FAILURE) {
3947
0
      RETURN_THROWS();
3948
0
    }
3949
0
  }
3950
0
  ZVAL_COPY_OR_DUP(return_value, &ref->value);
3951
0
}
3952
/* }}} */
3953
3954
/* {{{ Get the declaring class */
3955
ZEND_METHOD(ReflectionClassConstant, getDeclaringClass)
3956
18
{
3957
18
  const reflection_object *intern;
3958
18
  const zend_class_constant *ref;
3959
3960
18
  ZEND_PARSE_PARAMETERS_NONE();
3961
18
  GET_REFLECTION_OBJECT_PTR(ref);
3962
3963
18
  zend_reflection_class_factory(ref->ce, return_value);
3964
18
}
3965
/* }}} */
3966
3967
/* {{{ Returns the doc comment for this constant */
3968
ZEND_METHOD(ReflectionClassConstant, getDocComment)
3969
30
{
3970
30
  const reflection_object *intern;
3971
30
  const zend_class_constant *ref;
3972
3973
30
  ZEND_PARSE_PARAMETERS_NONE();
3974
30
  GET_REFLECTION_OBJECT_PTR(ref);
3975
30
  if (ref->doc_comment) {
3976
20
    RETURN_STR_COPY(ref->doc_comment);
3977
20
  }
3978
10
  RETURN_FALSE;
3979
10
}
3980
/* }}} */
3981
3982
/* {{{ Returns the attributes of this constant */
3983
ZEND_METHOD(ReflectionClassConstant, getAttributes)
3984
112
{
3985
112
  const reflection_object *intern;
3986
112
  zend_class_constant *ref;
3987
3988
112
  GET_REFLECTION_OBJECT_PTR(ref);
3989
3990
112
  reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
3991
112
    ref->attributes, 0, ref->ce, ZEND_ATTRIBUTE_TARGET_CLASS_CONST,
3992
112
    ref->ce->type == ZEND_USER_CLASS ? ref->ce->info.user.filename : NULL);
3993
112
}
3994
/* }}} */
3995
3996
ZEND_METHOD(ReflectionClassConstant, isEnumCase)
3997
6
{
3998
6
  _class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_CLASS_CONST_IS_CASE);
3999
6
}
4000
4001
ZEND_METHOD(ReflectionClassConstant, isDeprecated)
4002
1
{
4003
1
  _class_constant_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_DEPRECATED);
4004
1
}
4005
4006
/* {{{ reflection_class_object_ctor */
4007
static void reflection_class_object_ctor(INTERNAL_FUNCTION_PARAMETERS, bool is_object)
4008
4.47k
{
4009
4.47k
  zend_string *arg_class = NULL;
4010
4.47k
  zend_object *arg_obj;
4011
4012
4.47k
  if (is_object) {
4013
326
    ZEND_PARSE_PARAMETERS_START(1, 1)
4014
424
      Z_PARAM_OBJ(arg_obj)
4015
110
    ZEND_PARSE_PARAMETERS_END();
4016
4.36k
  } else {
4017
13.0k
    ZEND_PARSE_PARAMETERS_START(1, 1)
4018
21.7k
      Z_PARAM_OBJ_OR_STR(arg_obj, arg_class)
4019
21.7k
    ZEND_PARSE_PARAMETERS_END();
4020
4.36k
  }
4021
4022
4.46k
  zval *object = ZEND_THIS;
4023
4.46k
  reflection_object *intern = Z_REFLECTION_P(object);
4024
4025
  /* Note: class entry name is interned, no need to destroy them */
4026
4.46k
  if (arg_obj) {
4027
225
    ZVAL_STR_COPY(reflection_prop_name(object), arg_obj->ce->name);
4028
225
    intern->ptr = arg_obj->ce;
4029
225
    if (is_object) {
4030
103
      zval_ptr_dtor(&intern->obj);
4031
103
      ZVAL_OBJ_COPY(&intern->obj, arg_obj);
4032
103
    }
4033
4.23k
  } else {
4034
4.23k
    zend_class_entry *ce;
4035
4.23k
    if ((ce = zend_lookup_class(arg_class)) == NULL) {
4036
36
      if (!EG(exception)) {
4037
33
        zend_throw_exception_ex(reflection_exception_ptr, -1, "Class \"%pS\" does not exist", arg_class);
4038
33
      }
4039
36
      RETURN_THROWS();
4040
36
    }
4041
4042
4.20k
    ZVAL_STR_COPY(reflection_prop_name(object), ce->name);
4043
4.20k
    intern->ptr = ce;
4044
4.20k
  }
4045
4.42k
  intern->ref_type = REF_TYPE_OTHER;
4046
4.42k
}
4047
/* }}} */
4048
4049
/* {{{ Constructor. Takes a string or an instance as an argument */
4050
ZEND_METHOD(ReflectionClass, __construct)
4051
4.31k
{
4052
4.31k
  reflection_class_object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
4053
4.31k
}
4054
/* }}} */
4055
4056
/* {{{ add_class_vars */
4057
static void add_class_vars(zend_class_entry *ce, bool statics, zval *return_value)
4058
38
{
4059
38
  zval prop_copy;
4060
4061
180
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, zend_string *key, zend_property_info *prop_info) {
4062
180
    if ((prop_info->flags & ZEND_ACC_PRIVATE) && prop_info->ce != ce) {
4063
2
      continue;
4064
2
    }
4065
4066
180
    bool is_static = (prop_info->flags & ZEND_ACC_STATIC) != 0;
4067
50
    if (statics != is_static) {
4068
25
      continue;
4069
25
    }
4070
4071
25
    zval *prop = property_get_default(prop_info);
4072
25
    if (!prop || Z_ISUNDEF_P(prop)) {
4073
14
      continue;
4074
14
    }
4075
4076
    /* copy: enforce read only access */
4077
11
    ZVAL_DEREF(prop);
4078
11
    ZVAL_COPY_OR_DUP(&prop_copy, prop);
4079
4080
    /* this is necessary to make it able to work with default array
4081
    * properties, returned to user */
4082
11
    if (Z_TYPE(prop_copy) == IS_CONSTANT_AST
4083
0
      && UNEXPECTED(zval_update_constant_ex(&prop_copy, ce) != SUCCESS)
4084
11
    ) {
4085
0
      return;
4086
0
    }
4087
4088
11
    zend_hash_update(Z_ARRVAL_P(return_value), key, &prop_copy);
4089
11
  } ZEND_HASH_FOREACH_END();
4090
38
}
4091
/* }}} */
4092
4093
/* {{{ Returns an associative array containing all static property values of the class */
4094
ZEND_METHOD(ReflectionClass, getStaticProperties)
4095
6
{
4096
6
  const reflection_object *intern;
4097
6
  zend_class_entry *ce;
4098
4099
6
  ZEND_PARSE_PARAMETERS_NONE();
4100
4101
6
  GET_REFLECTION_OBJECT_PTR(ce);
4102
4103
6
  if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
4104
1
    RETURN_THROWS();
4105
1
  }
4106
4107
  // default_static_members_count includes inherited static members, see
4108
  // zend_do_inheritance_ex().
4109
  // PHP does not support *dynamic* static properties the same way non-static
4110
  // properties can be dynamic (i.e. present on an object without having been
4111
  // declared on the class). Thus, default_static_members_count will always
4112
  // reflect the count of all static members that a class might have.
4113
5
  if (ce->default_static_members_count == 0) {
4114
1
    RETURN_EMPTY_ARRAY();
4115
1
  }
4116
4117
4
  if (!CE_STATIC_MEMBERS(ce)) {
4118
2
    zend_class_init_statics(ce);
4119
2
  }
4120
4121
4
  array_init(return_value);
4122
4123
20
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, zend_string *key, zend_property_info *prop_info) {
4124
20
    if ((prop_info->flags & ZEND_ACC_PRIVATE) && prop_info->ce != ce) {
4125
0
      continue;
4126
0
    }
4127
6
    if ((prop_info->flags & ZEND_ACC_STATIC) == 0) {
4128
0
      continue;
4129
0
    }
4130
4131
6
    zval *prop = &CE_STATIC_MEMBERS(ce)[prop_info->offset];
4132
6
    ZVAL_DEINDIRECT(prop);
4133
4134
6
    if (ZEND_TYPE_IS_SET(prop_info->type) && Z_ISUNDEF_P(prop)) {
4135
0
      continue;
4136
0
    }
4137
4138
    /* enforce read only access */
4139
6
    ZVAL_DEREF(prop);
4140
6
    Z_TRY_ADDREF_P(prop);
4141
4142
6
    zend_hash_update(Z_ARRVAL_P(return_value), key, prop);
4143
6
  } ZEND_HASH_FOREACH_END();
4144
4
}
4145
/* }}} */
4146
4147
/* {{{ Returns the value of a static property */
4148
ZEND_METHOD(ReflectionClass, getStaticPropertyValue)
4149
1
{
4150
1
  const reflection_object *intern;
4151
1
  zend_class_entry *ce;
4152
1
  zend_string *name;
4153
1
  zval *def_value = NULL;
4154
4155
1
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|z", &name, &def_value) == FAILURE) {
4156
0
    RETURN_THROWS();
4157
0
  }
4158
4159
1
  GET_REFLECTION_OBJECT_PTR(ce);
4160
4161
1
  if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
4162
0
    RETURN_THROWS();
4163
0
  }
4164
4165
1
  const zend_class_entry *old_scope = EG(fake_scope);
4166
1
  EG(fake_scope) = ce;
4167
1
  zval *prop = zend_std_get_static_property(ce, name, BP_VAR_IS);
4168
1
  EG(fake_scope) = old_scope;
4169
4170
1
  if (prop && !Z_ISUNDEF_P(prop)) {
4171
0
    RETURN_COPY_DEREF(prop);
4172
0
  }
4173
4174
1
  if (def_value) {
4175
0
    RETURN_COPY(def_value);
4176
0
  }
4177
4178
1
  if (prop) {
4179
0
    zend_throw_error(NULL,
4180
0
      "Typed property %pS::$%pS must not be accessed before initialization", ce->name, name);
4181
1
  } else {
4182
1
    zend_throw_exception_ex(reflection_exception_ptr, 0,
4183
1
      "Property %pS::$%pS does not exist", ce->name, name);
4184
1
  }
4185
1
}
4186
/* }}} */
4187
4188
/* {{{ Sets the value of a static property */
4189
ZEND_METHOD(ReflectionClass, setStaticPropertyValue)
4190
2
{
4191
2
  const reflection_object *intern;
4192
2
  zend_class_entry *ce;
4193
2
  zend_string *name;
4194
2
  zval *value;
4195
4196
2
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "Sz", &name, &value) == FAILURE) {
4197
0
    RETURN_THROWS();
4198
0
  }
4199
4200
2
  GET_REFLECTION_OBJECT_PTR(ce);
4201
4202
2
  if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
4203
0
    RETURN_THROWS();
4204
0
  }
4205
2
  const zend_class_entry *old_scope = EG(fake_scope);
4206
2
  EG(fake_scope) = ce;
4207
2
  zend_property_info *prop_info;
4208
2
  zval *variable_ptr = zend_std_get_static_property_with_info(ce, name, BP_VAR_W, &prop_info);
4209
2
  EG(fake_scope) = old_scope;
4210
2
  if (!variable_ptr) {
4211
1
    zend_clear_exception();
4212
1
    zend_throw_exception_ex(reflection_exception_ptr, 0,
4213
1
        "Property %pS::$%pS does not exist", ce->name, name);
4214
1
    RETURN_THROWS();
4215
1
  }
4216
4217
1
  if (Z_ISREF_P(variable_ptr)) {
4218
0
    zend_reference *ref = Z_REF_P(variable_ptr);
4219
0
    variable_ptr = Z_REFVAL_P(variable_ptr);
4220
4221
0
    if (!zend_verify_ref_assignable_zval(ref, value, false)) {
4222
0
      return;
4223
0
    }
4224
0
  }
4225
4226
1
  if (ZEND_TYPE_IS_SET(prop_info->type) && !zend_verify_property_type(prop_info, value, false)) {
4227
0
    return;
4228
0
  }
4229
4230
1
  zval_ptr_dtor(variable_ptr);
4231
1
  ZVAL_COPY(variable_ptr, value);
4232
4233
1
}
4234
/* }}} */
4235
4236
/* {{{ Returns an associative array containing copies of all default property values of the class */
4237
ZEND_METHOD(ReflectionClass, getDefaultProperties)
4238
20
{
4239
20
  const reflection_object *intern;
4240
20
  zend_class_entry *ce;
4241
4242
20
  ZEND_PARSE_PARAMETERS_NONE();
4243
20
  GET_REFLECTION_OBJECT_PTR(ce);
4244
20
  array_init(return_value);
4245
20
  if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
4246
1
    RETURN_THROWS();
4247
1
  }
4248
19
  add_class_vars(ce, true, return_value);
4249
19
  add_class_vars(ce, false, return_value);
4250
19
}
4251
/* }}} */
4252
4253
/* {{{ Returns a string representation */
4254
ZEND_METHOD(ReflectionClass, __toString)
4255
496
{
4256
496
  reflection_object *intern;
4257
496
  zend_class_entry *ce;
4258
496
  smart_str str = {0};
4259
4260
496
  ZEND_PARSE_PARAMETERS_NONE();
4261
496
  GET_REFLECTION_OBJECT_PTR(ce);
4262
496
  _class_string(&str, ce, Z_ISUNDEF(intern->obj) ? NULL : Z_OBJ(intern->obj), "");
4263
496
  RETURN_STR(smart_str_extract(&str));
4264
496
}
4265
/* }}} */
4266
4267
/* {{{ Returns the class' name */
4268
ZEND_METHOD(ReflectionClass, getName)
4269
43
{
4270
43
  const reflection_object *intern;
4271
43
  const zend_class_entry *ce;
4272
4273
43
  ZEND_PARSE_PARAMETERS_NONE();
4274
4275
43
  GET_REFLECTION_OBJECT_PTR(ce);
4276
43
  RETURN_STR_COPY(ce->name);
4277
43
}
4278
/* }}} */
4279
4280
/* {{{ Returns whether this class is an internal class */
4281
ZEND_METHOD(ReflectionClass, isInternal)
4282
7
{
4283
7
  const reflection_object *intern;
4284
7
  const zend_class_entry *ce;
4285
4286
7
  ZEND_PARSE_PARAMETERS_NONE();
4287
7
  GET_REFLECTION_OBJECT_PTR(ce);
4288
7
  RETURN_BOOL(ce->type == ZEND_INTERNAL_CLASS);
4289
7
}
4290
/* }}} */
4291
4292
/* {{{ Returns whether this class is user-defined */
4293
ZEND_METHOD(ReflectionClass, isUserDefined)
4294
0
{
4295
0
  const reflection_object *intern;
4296
0
  const zend_class_entry *ce;
4297
4298
0
  ZEND_PARSE_PARAMETERS_NONE();
4299
0
  GET_REFLECTION_OBJECT_PTR(ce);
4300
0
  RETURN_BOOL(ce->type == ZEND_USER_CLASS);
4301
0
}
4302
/* }}} */
4303
4304
/* {{{ _class_check_flag */
4305
static void _class_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask)
4306
24
{
4307
24
  const reflection_object *intern;
4308
24
  const zend_class_entry *ce;
4309
4310
24
  ZEND_PARSE_PARAMETERS_NONE();
4311
24
  GET_REFLECTION_OBJECT_PTR(ce);
4312
24
  RETURN_BOOL(ce->ce_flags & mask);
4313
24
}
4314
/* }}} */
4315
4316
/* {{{ Returns whether this class is anonymous */
4317
ZEND_METHOD(ReflectionClass, isAnonymous)
4318
2
{
4319
2
  _class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_ANON_CLASS);
4320
2
}
4321
/* }}} */
4322
4323
/* {{{ Returns the filename of the file this class was declared in */
4324
ZEND_METHOD(ReflectionClass, getFileName)
4325
5
{
4326
5
  const reflection_object *intern;
4327
5
  const zend_class_entry *ce;
4328
4329
5
  ZEND_PARSE_PARAMETERS_NONE();
4330
5
  GET_REFLECTION_OBJECT_PTR(ce);
4331
5
  if (ce->type == ZEND_USER_CLASS) {
4332
4
    RETURN_STR_COPY(ce->info.user.filename);
4333
4
  }
4334
1
  RETURN_FALSE;
4335
1
}
4336
/* }}} */
4337
4338
/* {{{ Returns the line this class' declaration starts at */
4339
ZEND_METHOD(ReflectionClass, getStartLine)
4340
6
{
4341
6
  const reflection_object *intern;
4342
6
  const zend_class_entry *ce;
4343
4344
6
  ZEND_PARSE_PARAMETERS_NONE();
4345
6
  GET_REFLECTION_OBJECT_PTR(ce);
4346
6
  if (ce->type == ZEND_USER_CLASS) {
4347
5
    RETURN_LONG(ce->info.user.line_start);
4348
5
  }
4349
1
  RETURN_FALSE;
4350
1
}
4351
/* }}} */
4352
4353
/* {{{ Returns the line this class' declaration ends at */
4354
ZEND_METHOD(ReflectionClass, getEndLine)
4355
4
{
4356
4
  const reflection_object *intern;
4357
4
  const zend_class_entry *ce;
4358
4359
4
  ZEND_PARSE_PARAMETERS_NONE();
4360
4
  GET_REFLECTION_OBJECT_PTR(ce);
4361
4
  if (ce->type == ZEND_USER_CLASS) {
4362
3
    RETURN_LONG(ce->info.user.line_end);
4363
3
  }
4364
1
  RETURN_FALSE;
4365
1
}
4366
/* }}} */
4367
4368
/* {{{ Returns the doc comment for this class */
4369
ZEND_METHOD(ReflectionClass, getDocComment)
4370
24
{
4371
24
  const reflection_object *intern;
4372
24
  const zend_class_entry *ce;
4373
4374
24
  ZEND_PARSE_PARAMETERS_NONE();
4375
24
  GET_REFLECTION_OBJECT_PTR(ce);
4376
24
  if (ce->doc_comment) {
4377
19
    RETURN_STR_COPY(ce->doc_comment);
4378
19
  }
4379
5
  RETURN_FALSE;
4380
5
}
4381
/* }}} */
4382
4383
/* {{{ Returns the attributes for this class */
4384
ZEND_METHOD(ReflectionClass, getAttributes)
4385
432
{
4386
432
  const reflection_object *intern;
4387
432
  zend_class_entry *ce;
4388
4389
432
  GET_REFLECTION_OBJECT_PTR(ce);
4390
4391
432
  reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
4392
432
    ce->attributes, 0, ce, ZEND_ATTRIBUTE_TARGET_CLASS,
4393
432
    ce->type == ZEND_USER_CLASS ? ce->info.user.filename : NULL);
4394
432
}
4395
/* }}} */
4396
4397
/* {{{ Returns the class' constructor if there is one, NULL otherwise */
4398
ZEND_METHOD(ReflectionClass, getConstructor)
4399
0
{
4400
0
  const reflection_object *intern;
4401
0
  zend_class_entry *ce;
4402
4403
0
  ZEND_PARSE_PARAMETERS_NONE();
4404
0
  GET_REFLECTION_OBJECT_PTR(ce);
4405
4406
0
  if (ce->constructor) {
4407
0
    reflection_method_factory(ce, ce->constructor, NULL, return_value);
4408
0
  } else {
4409
0
    RETURN_NULL();
4410
0
  }
4411
0
}
4412
/* }}} */
4413
4414
/* {{{ Returns whether a method exists or not */
4415
ZEND_METHOD(ReflectionClass, hasMethod)
4416
3
{
4417
3
  const reflection_object *intern;
4418
3
  const zend_class_entry *ce;
4419
3
  zend_string *name;
4420
4421
3
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4422
0
    RETURN_THROWS();
4423
0
  }
4424
4425
3
  GET_REFLECTION_OBJECT_PTR(ce);
4426
3
  RETVAL_BOOL(zend_hash_find_ptr_lc(&ce->function_table, name) != NULL
4427
3
    || is_closure_invoke(ce, name));
4428
3
}
4429
/* }}} */
4430
4431
/* {{{ Returns the class' method specified by its name */
4432
ZEND_METHOD(ReflectionClass, getMethod)
4433
295
{
4434
295
  const reflection_object *intern;
4435
295
  zend_class_entry *ce;
4436
295
  zend_string *name;
4437
4438
295
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4439
0
    RETURN_THROWS();
4440
0
  }
4441
4442
295
  GET_REFLECTION_OBJECT_PTR(ce);
4443
295
  zend_function *mptr;
4444
295
  zval obj_tmp;
4445
295
  bool is_invoke = is_closure_invoke(ce, name);
4446
295
  if (!Z_ISUNDEF(intern->obj) && is_invoke
4447
2
    && (mptr = zend_get_closure_invoke_method(Z_OBJ(intern->obj))) != NULL)
4448
2
  {
4449
    /* don't assign closure_object since we only reflect the invoke handler
4450
       method and not the closure definition itself */
4451
2
    reflection_method_factory(ce, mptr, NULL, return_value);
4452
293
  } else if (Z_ISUNDEF(intern->obj) && is_invoke
4453
0
    && object_init_ex(&obj_tmp, ce) == SUCCESS && (mptr = zend_get_closure_invoke_method(Z_OBJ(obj_tmp))) != NULL) {
4454
    /* don't assign closure_object since we only reflect the invoke handler
4455
       method and not the closure definition itself */
4456
0
    reflection_method_factory(ce, mptr, NULL, return_value);
4457
0
    zval_ptr_dtor(&obj_tmp);
4458
293
  } else if ((mptr = zend_hash_find_ptr_lc(&ce->function_table, name)) != NULL) {
4459
286
    reflection_method_factory(ce, mptr, NULL, return_value);
4460
286
  } else {
4461
7
    zend_throw_exception_ex(reflection_exception_ptr, 0,
4462
7
        "Method %pS::%pS() does not exist", ce->name, name);
4463
7
  }
4464
295
}
4465
/* }}} */
4466
4467
/* {{{ _addmethod */
4468
static bool _addmethod(zend_function *mptr, zend_class_entry *ce, HashTable *ht, zend_long filter)
4469
59
{
4470
59
  if ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) && mptr->common.scope != ce) {
4471
0
    return false;
4472
0
  }
4473
4474
59
  if (mptr->common.fn_flags & filter) {
4475
44
    zval method;
4476
44
    reflection_method_factory(ce, mptr, NULL, &method);
4477
44
    zend_hash_next_index_insert_new(ht, &method);
4478
44
    return true;
4479
44
  }
4480
15
  return false;
4481
59
}
4482
/* }}} */
4483
4484
/* {{{ Returns an array of this class' methods */
4485
ZEND_METHOD(ReflectionClass, getMethods)
4486
15
{
4487
15
  const reflection_object *intern;
4488
15
  zend_class_entry *ce;
4489
15
  zend_long filter;
4490
15
  bool filter_is_null = true;
4491
4492
15
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l!", &filter, &filter_is_null) == FAILURE) {
4493
0
    RETURN_THROWS();
4494
0
  }
4495
4496
15
  if (filter_is_null) {
4497
12
    filter = ZEND_ACC_PPP_MASK | ZEND_ACC_ABSTRACT | ZEND_ACC_FINAL | ZEND_ACC_STATIC;
4498
12
  }
4499
4500
15
  GET_REFLECTION_OBJECT_PTR(ce);
4501
4502
15
  array_init(return_value);
4503
134
  ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, zend_function *mptr) {
4504
134
    _addmethod(mptr, ce, Z_ARRVAL_P(return_value), filter);
4505
134
  } ZEND_HASH_FOREACH_END();
4506
4507
  // No need for instanceof_function, the Closure class is final
4508
15
  if (ce != zend_ce_closure) {
4509
8
    return;
4510
8
  }
4511
15
  bool has_obj = Z_TYPE(intern->obj) != IS_UNDEF;
4512
7
  zval obj_tmp;
4513
7
  zend_object *obj;
4514
7
  if (!has_obj) {
4515
4
    object_init_ex(&obj_tmp, ce);
4516
4
    obj = Z_OBJ(obj_tmp);
4517
4
  } else {
4518
3
    obj = Z_OBJ(intern->obj);
4519
3
  }
4520
7
  zend_function *closure = zend_get_closure_invoke_method(obj);
4521
7
  if (closure
4522
7
    && !_addmethod(closure, ce, Z_ARRVAL_P(return_value), filter)
4523
7
  ) {
4524
2
    _free_function(closure);
4525
2
  }
4526
7
  if (!has_obj) {
4527
4
    zval_ptr_dtor(&obj_tmp);
4528
4
  }
4529
7
}
4530
/* }}} */
4531
4532
/* {{{ Returns whether a property exists or not */
4533
ZEND_METHOD(ReflectionClass, hasProperty)
4534
17
{
4535
17
  const reflection_object *intern;
4536
17
  const zend_class_entry *ce;
4537
17
  zend_string *name;
4538
4539
17
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4540
0
    RETURN_THROWS();
4541
0
  }
4542
4543
17
  GET_REFLECTION_OBJECT_PTR(ce);
4544
17
  zend_property_info *property_info;
4545
17
  if ((property_info = zend_hash_find_ptr(&ce->properties_info, name)) != NULL
4546
5
    && (!(property_info->flags & ZEND_ACC_PRIVATE)
4547
2
      || property_info->ce == ce)
4548
17
  ) {
4549
5
    RETURN_TRUE;
4550
5
  }
4551
12
  if (Z_TYPE(intern->obj) != IS_UNDEF) {
4552
9
    if (Z_OBJ_HANDLER(intern->obj, has_property)(Z_OBJ(intern->obj), name, ZEND_PROPERTY_EXISTS, NULL)) {
4553
0
      RETURN_TRUE;
4554
0
    }
4555
9
  }
4556
12
  RETURN_FALSE;
4557
12
}
4558
/* }}} */
4559
4560
/* {{{ Returns the class' property specified by its name */
4561
ZEND_METHOD(ReflectionClass, getProperty)
4562
1.43k
{
4563
1.43k
  const reflection_object *intern;
4564
1.43k
  zend_class_entry *ce;
4565
1.43k
  zend_string *name;
4566
4567
1.43k
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4568
0
    RETURN_THROWS();
4569
0
  }
4570
4571
1.43k
  GET_REFLECTION_OBJECT_PTR(ce);
4572
1.43k
  zend_property_info *property_info;
4573
1.43k
  if ((property_info = zend_hash_find_ptr(&ce->properties_info, name)) != NULL
4574
1.40k
    && (!(property_info->flags & ZEND_ACC_PRIVATE)
4575
42
      || property_info->ce == ce)
4576
1.43k
  ) {
4577
1.38k
    reflection_property_factory(ce, name, property_info, return_value);
4578
1.38k
    return;
4579
1.38k
  }
4580
47
  if (Z_TYPE(intern->obj) != IS_UNDEF) {
4581
    /* Check for dynamic properties */
4582
5
    if (zend_hash_exists(Z_OBJ_HT(intern->obj)->get_properties(Z_OBJ(intern->obj)), name)) {
4583
4
      reflection_property_factory(ce, name, NULL, return_value);
4584
4
      return;
4585
4
    }
4586
5
  }
4587
43
  const char *str_name = ZSTR_VAL(name);
4588
43
  const char *tmp;
4589
43
  size_t str_name_len;
4590
43
  bool fully_qualified = false;
4591
43
  if ((tmp = zend_memnstr(ZSTR_VAL(name), "::", 2, ZSTR_VAL(name) + ZSTR_LEN(name))) != NULL) {
4592
3
    fully_qualified = true;
4593
3
    size_t classname_len = tmp - ZSTR_VAL(name);
4594
3
    zend_string *classname = zend_string_init(ZSTR_VAL(name), classname_len, false);
4595
3
    str_name_len = ZSTR_LEN(name) - (classname_len + 2);
4596
3
    str_name = tmp + 2;
4597
4598
3
    zend_class_entry *ce2 = zend_lookup_class(classname);
4599
3
    if (!ce2) {
4600
0
      if (!EG(exception)) {
4601
0
        zend_throw_exception_ex(reflection_exception_ptr, -1, "Class \"%pS\" does not exist", classname);
4602
0
      }
4603
0
      zend_string_release_ex(classname, false);
4604
0
      RETURN_THROWS();
4605
0
    }
4606
3
    zend_string_release_ex(classname, false);
4607
4608
3
    if (!instanceof_function(ce, ce2)) {
4609
1
      ALLOCA_FLAG(use_heap);
4610
1
      zend_string *prop_name_zstr;
4611
1
      ZSTR_ALLOCA_INIT(prop_name_zstr, str_name, str_name_len, use_heap);
4612
1
      zend_throw_exception_ex(reflection_exception_ptr, -1, "Fully qualified property name %pS::$%pS does not specify a base class of %pS", ce2->name, prop_name_zstr, ce->name);
4613
1
      ZSTR_ALLOCA_FREE(prop_name_zstr, use_heap);
4614
4615
1
      RETURN_THROWS();
4616
1
    }
4617
2
    ce = ce2;
4618
4619
2
    property_info = zend_hash_str_find_ptr(&ce->properties_info, str_name, str_name_len);
4620
2
    if (property_info != NULL
4621
1
      && (!(property_info->flags & ZEND_ACC_PRIVATE)
4622
0
        || property_info->ce == ce)
4623
2
    ) {
4624
1
      reflection_property_factory_str(ce, str_name, str_name_len, property_info, return_value);
4625
1
      return;
4626
1
    }
4627
2
  }
4628
  // Can only use the existing `name` string if it wasn't fully qualified
4629
41
  if (fully_qualified) {
4630
1
    ALLOCA_FLAG(use_heap);
4631
1
    zend_string *prop_name_zstr;
4632
1
    ZSTR_ALLOCA_INIT(prop_name_zstr, str_name, str_name_len, use_heap);
4633
1
    zend_throw_exception_ex(reflection_exception_ptr, 0, "Property %pS::$%pS does not exist", ce->name, prop_name_zstr);
4634
1
    ZSTR_ALLOCA_FREE(prop_name_zstr, use_heap);
4635
40
  } else {
4636
40
    zend_throw_exception_ex(reflection_exception_ptr, 0, "Property %pS::$%pS does not exist", ce->name, name);
4637
40
  }
4638
41
}
4639
/* }}} */
4640
4641
/* {{{ _addproperty */
4642
static void _addproperty(zend_property_info *pptr, zend_string *key, zend_class_entry *ce, HashTable *ht, long filter)
4643
104
{
4644
104
  if ((pptr->flags & ZEND_ACC_PRIVATE) && pptr->ce != ce) {
4645
0
    return;
4646
0
  }
4647
4648
104
  if (pptr->flags & filter) {
4649
104
    zval property;
4650
104
    reflection_property_factory(ce, key, pptr, &property);
4651
104
    zend_hash_next_index_insert_new(ht, &property);
4652
104
  }
4653
104
}
4654
/* }}} */
4655
4656
/* {{{ _adddynproperty */
4657
static void _adddynproperty(zval *ptr, zend_string *key, zend_class_entry *ce, zval *retval)
4658
5
{
4659
  /* under some circumstances, the properties hash table may contain numeric
4660
   * properties (e.g. when casting from array). This is a WON'T FIX bug, at
4661
   * least for the moment. Ignore these */
4662
5
  if (key == NULL) {
4663
0
    return;
4664
0
  }
4665
4666
  /* Not a dynamic property */
4667
5
  if (Z_TYPE_P(ptr) == IS_INDIRECT) {
4668
0
    return;
4669
0
  }
4670
4671
5
  zval property;
4672
5
  reflection_property_factory(ce, key, NULL, &property);
4673
5
  add_next_index_zval(retval, &property);
4674
5
}
4675
/* }}} */
4676
4677
/* {{{ Returns an array of this class' properties */
4678
ZEND_METHOD(ReflectionClass, getProperties)
4679
47
{
4680
47
  const reflection_object *intern;
4681
47
  zend_class_entry *ce;
4682
47
  zend_long filter;
4683
47
  bool filter_is_null = true;
4684
4685
47
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l!", &filter, &filter_is_null) == FAILURE) {
4686
0
    RETURN_THROWS();
4687
0
  }
4688
4689
47
  if (filter_is_null) {
4690
43
    filter = ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC;
4691
43
  }
4692
4693
47
  GET_REFLECTION_OBJECT_PTR(ce);
4694
4695
47
  array_init(return_value);
4696
47
  zend_string *key;
4697
302
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, key, zend_property_info *prop_info) {
4698
302
    _addproperty(prop_info, key, ce, Z_ARRVAL_P(return_value), filter);
4699
302
  } ZEND_HASH_FOREACH_END();
4700
4701
47
  if (Z_TYPE(intern->obj) != IS_UNDEF && (filter & ZEND_ACC_PUBLIC) != 0) {
4702
5
    HashTable *properties = Z_OBJ_HT(intern->obj)->get_properties(Z_OBJ(intern->obj));
4703
15
    ZEND_HASH_FOREACH_STR_KEY_VAL(properties, key, zval *prop) {
4704
15
      _adddynproperty(prop, key, ce, return_value);
4705
15
    } ZEND_HASH_FOREACH_END();
4706
5
  }
4707
47
}
4708
/* }}} */
4709
4710
/* {{{ Returns whether a constant exists or not */
4711
ZEND_METHOD(ReflectionClass, hasConstant)
4712
6
{
4713
6
  const reflection_object *intern;
4714
6
  const zend_class_entry *ce;
4715
6
  zend_string *name;
4716
4717
6
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4718
0
    RETURN_THROWS();
4719
0
  }
4720
4721
6
  GET_REFLECTION_OBJECT_PTR(ce);
4722
6
  RETURN_BOOL(zend_hash_exists(&ce->constants_table, name));
4723
6
}
4724
/* }}} */
4725
4726
/* {{{ Returns an associative array containing this class' constants and their values */
4727
ZEND_METHOD(ReflectionClass, getConstants)
4728
10
{
4729
10
  const reflection_object *intern;
4730
10
  const zend_class_entry *ce;
4731
10
  zend_long filter;
4732
10
  bool filter_is_null = true;
4733
4734
10
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l!", &filter, &filter_is_null) == FAILURE) {
4735
1
    RETURN_THROWS();
4736
1
  }
4737
4738
9
  if (filter_is_null) {
4739
7
    filter = ZEND_ACC_PPP_MASK;
4740
7
  }
4741
4742
9
  GET_REFLECTION_OBJECT_PTR(ce);
4743
4744
9
  const HashTable *constants_table = CE_CONSTANTS_TABLE(ce);
4745
9
  if (zend_hash_num_elements(constants_table) == 0) {
4746
0
    RETURN_EMPTY_ARRAY();
4747
0
  }
4748
4749
9
  array_init(return_value);
4750
9
  zval val;
4751
46
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(constants_table, zend_string *key, zend_class_constant *constant) {
4752
46
    if (UNEXPECTED(Z_TYPE(constant->value) == IS_CONSTANT_AST && zend_update_class_constant(constant, key, constant->ce) != SUCCESS)) {
4753
1
      RETURN_THROWS();
4754
1
    }
4755
4756
13
    if (ZEND_CLASS_CONST_FLAGS(constant) & filter) {
4757
12
      ZVAL_COPY_OR_DUP(&val, &constant->value);
4758
12
      zend_hash_add_new(Z_ARRVAL_P(return_value), key, &val);
4759
12
    }
4760
13
  } ZEND_HASH_FOREACH_END();
4761
9
}
4762
/* }}} */
4763
4764
/* {{{ Returns an associative array containing this class' constants as ReflectionClassConstant objects */
4765
ZEND_METHOD(ReflectionClass, getReflectionConstants)
4766
0
{
4767
0
  const reflection_object *intern;
4768
0
  zend_class_entry *ce;
4769
0
  zend_long filter;
4770
0
  bool filter_is_null = true;
4771
4772
0
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "|l!", &filter, &filter_is_null) == FAILURE) {
4773
0
    RETURN_THROWS();
4774
0
  }
4775
4776
0
  if (filter_is_null) {
4777
0
    filter = ZEND_ACC_PPP_MASK;
4778
0
  }
4779
4780
0
  GET_REFLECTION_OBJECT_PTR(ce);
4781
4782
0
  const HashTable *constants_table = CE_CONSTANTS_TABLE(ce);
4783
0
  if (zend_hash_num_elements(constants_table) == 0) {
4784
0
    RETURN_EMPTY_ARRAY();
4785
0
  }
4786
4787
0
  array_init(return_value);
4788
0
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(constants_table, zend_string *name, zend_class_constant *constant) {
4789
0
    if (ZEND_CLASS_CONST_FLAGS(constant) & filter) {
4790
0
      zval class_const;
4791
0
      reflection_class_constant_factory(name, constant, &class_const);
4792
0
      zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &class_const);
4793
0
    }
4794
0
  } ZEND_HASH_FOREACH_END();
4795
0
}
4796
/* }}} */
4797
4798
/* {{{ Returns the class' constant specified by its name */
4799
ZEND_METHOD(ReflectionClass, getConstant)
4800
44
{
4801
44
  const reflection_object *intern;
4802
44
  zend_class_entry *ce;
4803
44
  zend_string *name;
4804
4805
44
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4806
0
    RETURN_THROWS();
4807
0
  }
4808
4809
44
  GET_REFLECTION_OBJECT_PTR(ce);
4810
44
  const HashTable *constants_table = CE_CONSTANTS_TABLE(ce);
4811
44
  zend_class_constant *c;
4812
198
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(constants_table, zend_string *key, c) {
4813
198
    if (UNEXPECTED(Z_TYPE(c->value) == IS_CONSTANT_AST && zend_update_class_constant(c, key, c->ce) != SUCCESS)) {
4814
2
      RETURN_THROWS();
4815
2
    }
4816
198
  } ZEND_HASH_FOREACH_END();
4817
42
  if ((c = zend_hash_find_ptr(constants_table, name)) == NULL) {
4818
9
    zend_error(
4819
9
      E_DEPRECATED,
4820
9
      "ReflectionClass::getConstant() for a non-existent constant is deprecated, "
4821
9
        "use ReflectionClass::hasConstant() to check if the constant exists"
4822
9
    );
4823
9
    RETURN_FALSE;
4824
9
  }
4825
33
  ZVAL_COPY_OR_DUP(return_value, &c->value);
4826
33
}
4827
/* }}} */
4828
4829
/* {{{ Returns the class' constant as ReflectionClassConstant objects */
4830
ZEND_METHOD(ReflectionClass, getReflectionConstant)
4831
88
{
4832
88
  const reflection_object *intern;
4833
88
  zend_class_entry *ce;
4834
88
  zend_string *name;
4835
4836
88
  GET_REFLECTION_OBJECT_PTR(ce);
4837
88
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
4838
0
    RETURN_THROWS();
4839
0
  }
4840
4841
88
  zend_class_constant *constant;
4842
88
  if ((constant = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), name)) == NULL) {
4843
5
    RETURN_FALSE;
4844
5
  }
4845
83
  reflection_class_constant_factory(name, constant, return_value);
4846
83
}
4847
/* }}} */
4848
4849
/* {{{ Returns whether this class is instantiable */
4850
ZEND_METHOD(ReflectionClass, isInstantiable)
4851
2
{
4852
2
  const reflection_object *intern;
4853
2
  const zend_class_entry *ce;
4854
4855
2
  ZEND_PARSE_PARAMETERS_NONE();
4856
2
  GET_REFLECTION_OBJECT_PTR(ce);
4857
2
  if (ce->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_ENUM)) {
4858
2
    RETURN_FALSE;
4859
2
  }
4860
4861
  /* Basically, the class is instantiable. Though, if there is a constructor
4862
   * and it is not publicly accessible, it isn't! */
4863
0
  if (!ce->constructor) {
4864
0
    RETURN_TRUE;
4865
0
  }
4866
4867
0
  RETURN_BOOL(ce->constructor->common.fn_flags & ZEND_ACC_PUBLIC);
4868
0
}
4869
/* }}} */
4870
4871
/* {{{ Returns whether this class is cloneable */
4872
ZEND_METHOD(ReflectionClass, isCloneable)
4873
8
{
4874
8
  const reflection_object *intern;
4875
8
  zend_class_entry *ce;
4876
4877
8
  ZEND_PARSE_PARAMETERS_NONE();
4878
8
  GET_REFLECTION_OBJECT_PTR(ce);
4879
8
  if (ce->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS | ZEND_ACC_ENUM)) {
4880
7
    RETURN_FALSE;
4881
7
  }
4882
1
  if (ce->clone) {
4883
0
    RETURN_BOOL(ce->clone->common.fn_flags & ZEND_ACC_PUBLIC);
4884
0
  }
4885
1
  if (!Z_ISUNDEF(intern->obj)) {
4886
0
    RETURN_BOOL(Z_OBJ_HANDLER(intern->obj, clone_obj) != NULL);
4887
1
  } else {
4888
1
    zval obj;
4889
1
    if (UNEXPECTED(object_init_ex(&obj, ce) != SUCCESS)) {
4890
0
      return;
4891
0
    }
4892
    /* We're not calling the constructor, so don't call the destructor either. */
4893
1
    zend_object_store_ctor_failed(Z_OBJ(obj));
4894
1
    RETVAL_BOOL(Z_OBJ_HANDLER(obj, clone_obj) != NULL);
4895
1
    zval_ptr_dtor(&obj);
4896
1
  }
4897
1
}
4898
/* }}} */
4899
4900
/* {{{ Returns whether this is an interface or a class */
4901
ZEND_METHOD(ReflectionClass, isInterface)
4902
0
{
4903
0
  _class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_INTERFACE);
4904
0
}
4905
/* }}} */
4906
4907
/* {{{ Returns whether this is a trait */
4908
ZEND_METHOD(ReflectionClass, isTrait)
4909
6
{
4910
6
  _class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_TRAIT);
4911
6
}
4912
/* }}} */
4913
4914
ZEND_METHOD(ReflectionClass, isEnum)
4915
3
{
4916
3
  _class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_ENUM);
4917
3
}
4918
4919
/* {{{ Returns whether this class is final */
4920
ZEND_METHOD(ReflectionClass, isFinal)
4921
6
{
4922
6
  _class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_FINAL);
4923
6
}
4924
/* }}} */
4925
4926
/* Returns whether this class is readonly */
4927
ZEND_METHOD(ReflectionClass, isReadOnly)
4928
4
{
4929
4
  _class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_READONLY_CLASS);
4930
4
}
4931
4932
/* {{{ Returns whether this class is abstract */
4933
ZEND_METHOD(ReflectionClass, isAbstract)
4934
3
{
4935
3
  _class_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS);
4936
3
}
4937
/* }}} */
4938
4939
/* {{{ Returns a bitfield of the modifiers for this class */
4940
ZEND_METHOD(ReflectionClass, getModifiers)
4941
5
{
4942
5
  const reflection_object *intern;
4943
5
  const zend_class_entry *ce;
4944
5
  uint32_t keep_flags = ZEND_ACC_FINAL | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS | ZEND_ACC_READONLY_CLASS;
4945
4946
5
  ZEND_PARSE_PARAMETERS_NONE();
4947
4
  GET_REFLECTION_OBJECT_PTR(ce);
4948
4949
4
  RETURN_LONG((ce->ce_flags & keep_flags));
4950
4
}
4951
/* }}} */
4952
4953
/* {{{ Returns whether the given object is an instance of this class */
4954
ZEND_METHOD(ReflectionClass, isInstance)
4955
0
{
4956
0
  const reflection_object *intern;
4957
0
  const zend_class_entry *ce;
4958
0
  const zval *object;
4959
4960
0
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "o", &object) == FAILURE) {
4961
0
    RETURN_THROWS();
4962
0
  }
4963
0
  GET_REFLECTION_OBJECT_PTR(ce);
4964
0
  RETURN_BOOL(instanceof_function(Z_OBJCE_P(object), ce));
4965
0
}
4966
/* }}} */
4967
4968
/* {{{ Returns an instance of this class */
4969
ZEND_METHOD(ReflectionClass, newInstance)
4970
24
{
4971
24
  const reflection_object *intern;
4972
24
  zend_class_entry *ce;
4973
4974
24
  GET_REFLECTION_OBJECT_PTR(ce);
4975
4976
24
  if (UNEXPECTED(object_init_ex(return_value, ce) != SUCCESS)) {
4977
4
    return;
4978
4
  }
4979
4980
20
  const zend_class_entry *old_scope = EG(fake_scope);
4981
20
  EG(fake_scope) = ce;
4982
20
  zend_function *constructor = Z_OBJ_HT_P(return_value)->get_constructor(Z_OBJ_P(return_value));
4983
20
  EG(fake_scope) = old_scope;
4984
4985
  /* Run the constructor if there is one */
4986
20
  if (constructor) {
4987
18
    if (!(constructor->common.fn_flags & ZEND_ACC_PUBLIC)) {
4988
0
      zend_throw_exception_ex(reflection_exception_ptr, 0, "Access to non-public constructor of class %pS", ce->name);
4989
0
      zval_ptr_dtor(return_value);
4990
0
      RETURN_NULL();
4991
0
    }
4992
4993
18
    zval *params;
4994
18
    uint32_t num_args;
4995
18
    HashTable *named_params;
4996
54
    ZEND_PARSE_PARAMETERS_START(0, -1)
4997
54
      Z_PARAM_VARIADIC_WITH_NAMED(params, num_args, named_params)
4998
54
    ZEND_PARSE_PARAMETERS_END();
4999
5000
18
    zend_call_known_function(
5001
18
      constructor, Z_OBJ_P(return_value), Z_OBJCE_P(return_value), NULL,
5002
18
      num_args, params, named_params);
5003
5004
18
    if (EG(exception)) {
5005
0
      zend_object_store_ctor_failed(Z_OBJ_P(return_value));
5006
0
    }
5007
18
  } else if (ZEND_NUM_ARGS()) {
5008
0
    zend_throw_exception_ex(reflection_exception_ptr, 0, "Class %pS does not have a constructor, so you cannot pass any constructor arguments", ce->name);
5009
0
  }
5010
20
}
5011
/* }}} */
5012
5013
/* {{{ Returns an instance of this class without invoking its constructor */
5014
ZEND_METHOD(ReflectionClass, newInstanceWithoutConstructor)
5015
157
{
5016
157
  const reflection_object *intern;
5017
157
  zend_class_entry *ce;
5018
5019
157
  GET_REFLECTION_OBJECT_PTR(ce);
5020
5021
157
  ZEND_PARSE_PARAMETERS_NONE();
5022
5023
157
  if (ce->type == ZEND_INTERNAL_CLASS
5024
124
      && ce->create_object != NULL && (ce->ce_flags & ZEND_ACC_FINAL)) {
5025
22
    zend_throw_exception_ex(reflection_exception_ptr, 0, "Class %pS is an internal class marked as final that cannot be instantiated without invoking its constructor", ce->name);
5026
22
    RETURN_THROWS();
5027
22
  }
5028
5029
135
  object_init_ex(return_value, ce);
5030
135
}
5031
/* }}} */
5032
5033
/* {{{ Returns an instance of this class */
5034
ZEND_METHOD(ReflectionClass, newInstanceArgs)
5035
16
{
5036
16
  const reflection_object *intern;
5037
16
  zend_class_entry *ce;
5038
16
  HashTable *args = NULL;
5039
5040
16
  GET_REFLECTION_OBJECT_PTR(ce);
5041
5042
16
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "|h", &args) == FAILURE) {
5043
1
    RETURN_THROWS();
5044
1
  }
5045
5046
15
  uint32_t argc = 0;
5047
15
  if (args) {
5048
15
    argc = zend_hash_num_elements(args);
5049
15
  }
5050
5051
15
  if (UNEXPECTED(object_init_ex(return_value, ce) != SUCCESS)) {
5052
0
    return;
5053
0
  }
5054
5055
15
  const zend_class_entry *old_scope = EG(fake_scope);
5056
15
  EG(fake_scope) = ce;
5057
15
  zend_function *constructor = Z_OBJ_HT_P(return_value)->get_constructor(Z_OBJ_P(return_value));
5058
15
  EG(fake_scope) = old_scope;
5059
5060
  /* Run the constructor if there is one */
5061
15
  if (constructor) {
5062
13
    if (!(constructor->common.fn_flags & ZEND_ACC_PUBLIC)) {
5063
0
      zend_throw_exception_ex(reflection_exception_ptr, 0, "Access to non-public constructor of class %pS", ce->name);
5064
0
      zval_ptr_dtor(return_value);
5065
0
      RETURN_NULL();
5066
0
    }
5067
5068
13
    zend_call_known_function(
5069
13
      constructor, Z_OBJ_P(return_value), Z_OBJCE_P(return_value), NULL, 0, NULL, args);
5070
5071
13
    if (EG(exception)) {
5072
0
      zend_object_store_ctor_failed(Z_OBJ_P(return_value));
5073
0
    }
5074
13
  } else if (argc) {
5075
1
    zend_throw_exception_ex(reflection_exception_ptr, 0, "Class %pS does not have a constructor, so you cannot pass any constructor arguments", ce->name);
5076
1
  }
5077
15
}
5078
/* }}} */
5079
5080
void reflection_class_new_lazy(INTERNAL_FUNCTION_PARAMETERS,
5081
    int strategy, bool is_reset)
5082
3.15k
{
5083
3.15k
  const reflection_object *intern;
5084
3.15k
  zend_object *obj;
5085
3.15k
  zend_class_entry *ce;
5086
3.15k
  zend_fcall_info fci;
5087
3.15k
  zend_fcall_info_cache fcc;
5088
3.15k
  zend_long options = 0;
5089
5090
3.15k
  ZEND_ASSERT(strategy == ZEND_LAZY_OBJECT_STRATEGY_GHOST
5091
3.15k
      || strategy == ZEND_LAZY_OBJECT_STRATEGY_PROXY);
5092
5093
3.15k
  GET_REFLECTION_OBJECT_PTR(ce);
5094
5095
3.15k
  if (is_reset) {
5096
1.16k
    ZEND_PARSE_PARAMETERS_START(2, 3)
5097
1.54k
      Z_PARAM_OBJ_OF_CLASS(obj, ce)
5098
1.90k
      Z_PARAM_FUNC(fci, fcc)
5099
378
      Z_PARAM_OPTIONAL
5100
832
      Z_PARAM_LONG(options)
5101
388
    ZEND_PARSE_PARAMETERS_END();
5102
2.76k
  } else {
5103
8.29k
    ZEND_PARSE_PARAMETERS_START(1, 2)
5104
11.0k
      Z_PARAM_FUNC(fci, fcc)
5105
2.75k
      Z_PARAM_OPTIONAL
5106
5.65k
      Z_PARAM_LONG(options)
5107
2.76k
    ZEND_PARSE_PARAMETERS_END();
5108
2.75k
    obj = NULL;
5109
2.75k
  }
5110
5111
3.13k
  if (options & ~ZEND_LAZY_OBJECT_USER_MASK) {
5112
26
    uint32_t arg_num = 2 + is_reset;
5113
26
    zend_argument_error(reflection_exception_ptr, arg_num,
5114
26
        "contains invalid flags");
5115
26
    RETURN_THROWS();
5116
26
  }
5117
5118
3.10k
  if (!is_reset && (options & ZEND_LAZY_OBJECT_SKIP_DESTRUCTOR)) {
5119
7
    zend_argument_error(reflection_exception_ptr, 2,
5120
7
        "does not accept ReflectionClass::SKIP_DESTRUCTOR");
5121
7
    RETURN_THROWS();
5122
7
  }
5123
5124
3.10k
  if (is_reset) {
5125
364
    if (zend_object_is_lazy(obj) && !zend_lazy_object_initialized(obj)) {
5126
17
      zend_throw_exception_ex(reflection_exception_ptr, 0, "Object is already lazy");
5127
17
      RETURN_THROWS();
5128
17
    }
5129
2.73k
  } else {
5130
2.73k
    obj = NULL;
5131
2.73k
  }
5132
5133
3.08k
  if (!fcc.function_handler) {
5134
    /* Call trampoline has been cleared by zpp. Refetch it, because we want to deal
5135
     * with it ourselves. It is important that it is not refetched on every call,
5136
     * because calls may occur from different scopes. */
5137
0
    zend_is_callable_ex(&fci.function_name, NULL, 0, NULL, &fcc, NULL);
5138
0
  }
5139
5140
3.08k
  obj = zend_object_make_lazy(obj, ce, &fci.function_name, &fcc,
5141
3.08k
      strategy | options);
5142
5143
3.08k
  if (!obj) {
5144
68
    RETURN_THROWS();
5145
68
  }
5146
5147
3.01k
  if (!is_reset) {
5148
2.71k
    RETURN_OBJ(obj);
5149
2.71k
  }
5150
3.01k
}
5151
5152
/* {{{ Instantiates a lazy instance, using the ghost strategy */
5153
PHP_METHOD(ReflectionClass, newLazyGhost)
5154
1.46k
{
5155
1.46k
  reflection_class_new_lazy(INTERNAL_FUNCTION_PARAM_PASSTHRU,
5156
1.46k
      ZEND_LAZY_OBJECT_STRATEGY_GHOST, /* is_reset */ false);
5157
1.46k
}
5158
/* }}} */
5159
5160
/* {{{ Instantiates a lazy instance, using the proxy strategy */
5161
PHP_METHOD(ReflectionClass, newLazyProxy)
5162
1.30k
{
5163
1.30k
  reflection_class_new_lazy(INTERNAL_FUNCTION_PARAM_PASSTHRU,
5164
1.30k
      ZEND_LAZY_OBJECT_STRATEGY_PROXY, /* is_reset */ false);
5165
1.30k
}
5166
/* }}} */
5167
5168
/* {{{ Reset an object and make it lazy, using the ghost strategy */
5169
PHP_METHOD(ReflectionClass, resetAsLazyGhost)
5170
193
{
5171
193
  reflection_class_new_lazy(INTERNAL_FUNCTION_PARAM_PASSTHRU,
5172
193
      ZEND_LAZY_OBJECT_STRATEGY_GHOST, /* is_reset */ true);
5173
193
}
5174
/* }}} */
5175
5176
/* {{{ Reset an object and make it lazy, using the proxy strategy */
5177
PHP_METHOD(ReflectionClass, resetAsLazyProxy)
5178
195
{
5179
195
  reflection_class_new_lazy(INTERNAL_FUNCTION_PARAM_PASSTHRU,
5180
195
      ZEND_LAZY_OBJECT_STRATEGY_PROXY, /* is_reset */ true);
5181
195
}
5182
/* }}} */
5183
5184
/* {{{ Returns whether object lazy and uninitialized */
5185
ZEND_METHOD(ReflectionClass, isUninitializedLazyObject)
5186
610
{
5187
610
  const reflection_object *intern;
5188
610
  zend_class_entry *ce;
5189
610
  zend_object *object;
5190
5191
610
  GET_REFLECTION_OBJECT_PTR(ce);
5192
5193
1.83k
  ZEND_PARSE_PARAMETERS_START(1, 1)
5194
2.44k
    Z_PARAM_OBJ_OF_CLASS(object, ce)
5195
610
  ZEND_PARSE_PARAMETERS_END();
5196
5197
605
  RETURN_BOOL(zend_object_is_lazy(object) && !zend_lazy_object_initialized(object));
5198
605
}
5199
/* }}} */
5200
5201
/* {{{ Trigger object initialization */
5202
ZEND_METHOD(ReflectionClass, initializeLazyObject)
5203
652
{
5204
652
  const reflection_object *intern;
5205
652
  zend_class_entry *ce;
5206
652
  zend_object *object;
5207
5208
652
  GET_REFLECTION_OBJECT_PTR(ce);
5209
5210
1.95k
  ZEND_PARSE_PARAMETERS_START(1, 1)
5211
2.60k
    Z_PARAM_OBJ_OF_CLASS(object, ce)
5212
652
  ZEND_PARSE_PARAMETERS_END();
5213
5214
647
  if (zend_object_is_lazy(object)
5215
606
      && !zend_lazy_object_initialized(object)) {
5216
551
    zend_lazy_object_init(object);
5217
551
  }
5218
5219
647
  if (zend_lazy_object_initialized(object)) {
5220
551
    RETURN_OBJ_COPY(zend_lazy_object_get_instance(object));
5221
551
  } else {
5222
96
    RETURN_THROWS();
5223
96
  }
5224
647
}
5225
/* }}} */
5226
5227
/* {{{ Mark object as initialized without calling the initializer */
5228
ZEND_METHOD(ReflectionClass, markLazyObjectAsInitialized)
5229
18
{
5230
18
  const reflection_object *intern;
5231
18
  zend_class_entry *ce;
5232
18
  zend_object *object;
5233
5234
18
  GET_REFLECTION_OBJECT_PTR(ce);
5235
5236
54
  ZEND_PARSE_PARAMETERS_START(1, 1)
5237
72
    Z_PARAM_OBJ_OF_CLASS(object, ce)
5238
18
  ZEND_PARSE_PARAMETERS_END();
5239
5240
18
  if (zend_object_is_lazy(object)
5241
18
      && !zend_lazy_object_initialized(object)) {
5242
18
    zend_lazy_object_mark_as_initialized(object);
5243
18
  }
5244
5245
18
  if (zend_lazy_object_initialized(object)) {
5246
18
    RETURN_OBJ_COPY(zend_lazy_object_get_instance(object));
5247
18
  } else {
5248
0
    RETURN_THROWS();
5249
0
  }
5250
18
}
5251
/* }}} */
5252
5253
/* {{{ Get lazy object initializer */
5254
ZEND_METHOD(ReflectionClass, getLazyInitializer)
5255
157
{
5256
157
  const reflection_object *intern;
5257
157
  zend_class_entry *ce;
5258
157
  zend_object *object;
5259
5260
157
  GET_REFLECTION_OBJECT_PTR(ce);
5261
5262
471
  ZEND_PARSE_PARAMETERS_START(1, 1)
5263
628
    Z_PARAM_OBJ_OF_CLASS(object, ce)
5264
157
  ZEND_PARSE_PARAMETERS_END();
5265
5266
154
  if (!zend_object_is_lazy(object)
5267
101
    || zend_lazy_object_initialized(object)
5268
154
  ) {
5269
53
    RETURN_NULL();
5270
53
  }
5271
5272
101
  RETURN_ZVAL(zend_lazy_object_get_initializer_zv(object), true, false);
5273
101
}
5274
/* }}} */
5275
5276
/* {{{ Returns an array of interfaces this class implements */
5277
ZEND_METHOD(ReflectionClass, getInterfaces)
5278
1
{
5279
1
  const reflection_object *intern;
5280
1
  const zend_class_entry *ce;
5281
5282
1
  ZEND_PARSE_PARAMETERS_NONE();
5283
1
  GET_REFLECTION_OBJECT_PTR(ce);
5284
5285
1
  if (ce->num_interfaces) {
5286
1
    ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
5287
1
    array_init(return_value);
5288
7
    for (uint32_t i=0; i < ce->num_interfaces; i++) {
5289
6
      zval interface;
5290
6
      zend_reflection_class_factory(ce->interfaces[i], &interface);
5291
6
      zend_hash_update(Z_ARRVAL_P(return_value), ce->interfaces[i]->name, &interface);
5292
6
    }
5293
1
  } else {
5294
0
    RETURN_EMPTY_ARRAY();
5295
0
  }
5296
1
}
5297
/* }}} */
5298
5299
/* {{{ Returns an array of names of interfaces this class implements */
5300
ZEND_METHOD(ReflectionClass, getInterfaceNames)
5301
28
{
5302
28
  const reflection_object *intern;
5303
28
  const zend_class_entry *ce;
5304
5305
28
  ZEND_PARSE_PARAMETERS_NONE();
5306
28
  GET_REFLECTION_OBJECT_PTR(ce);
5307
5308
28
  if (!ce->num_interfaces) {
5309
    /* Return an empty array if this class implements no interfaces */
5310
11
    RETURN_EMPTY_ARRAY();
5311
11
  }
5312
5313
17
  ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
5314
17
  array_init(return_value);
5315
5316
35
  for (uint32_t i=0; i < ce->num_interfaces; i++) {
5317
18
    add_next_index_str(return_value, zend_string_copy(ce->interfaces[i]->name));
5318
18
  }
5319
17
}
5320
/* }}} */
5321
5322
/* {{{ Returns an array of traits used by this class */
5323
ZEND_METHOD(ReflectionClass, getTraits)
5324
4
{
5325
4
  const reflection_object *intern;
5326
4
  const zend_class_entry *ce;
5327
5328
4
  ZEND_PARSE_PARAMETERS_NONE();
5329
4
  GET_REFLECTION_OBJECT_PTR(ce);
5330
5331
4
  if (!ce->num_traits) {
5332
2
    RETURN_EMPTY_ARRAY();
5333
2
  }
5334
5335
2
  array_init(return_value);
5336
5337
5
  for (uint32_t i=0; i < ce->num_traits; i++) {
5338
3
    zval trait;
5339
5340
3
    zend_class_entry *trait_ce = zend_fetch_class_by_name(ce->trait_names[i].name,
5341
3
      ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT);
5342
3
    ZEND_ASSERT(trait_ce);
5343
3
    zend_reflection_class_factory(trait_ce, &trait);
5344
3
    zend_hash_update(Z_ARRVAL_P(return_value), ce->trait_names[i].name, &trait);
5345
3
  }
5346
2
}
5347
/* }}} */
5348
5349
/* {{{ Returns an array of names of traits used by this class */
5350
ZEND_METHOD(ReflectionClass, getTraitNames)
5351
4
{
5352
4
  const reflection_object *intern;
5353
4
  const zend_class_entry *ce;
5354
5355
4
  ZEND_PARSE_PARAMETERS_NONE();
5356
4
  GET_REFLECTION_OBJECT_PTR(ce);
5357
5358
4
  if (!ce->num_traits) {
5359
2
    RETURN_EMPTY_ARRAY();
5360
2
  }
5361
5362
2
  array_init(return_value);
5363
5364
5
  for (uint32_t i=0; i < ce->num_traits; i++) {
5365
3
    add_next_index_str(return_value, zend_string_copy(ce->trait_names[i].name));
5366
3
  }
5367
2
}
5368
/* }}} */
5369
5370
/* {{{ Returns an array of trait aliases */
5371
ZEND_METHOD(ReflectionClass, getTraitAliases)
5372
8
{
5373
8
  const reflection_object *intern;
5374
8
  const zend_class_entry *ce;
5375
5376
8
  ZEND_PARSE_PARAMETERS_NONE();
5377
8
  GET_REFLECTION_OBJECT_PTR(ce);
5378
5379
8
  if (!ce->trait_aliases) {
5380
0
    RETURN_EMPTY_ARRAY();
5381
0
  }
5382
5383
8
  array_init(return_value);
5384
16
  for (uint32_t i = 0; ce->trait_aliases[i]; i++) {
5385
8
    const zend_trait_method_reference *cur_ref = &ce->trait_aliases[i]->trait_method;
5386
5387
8
    if (!ce->trait_aliases[i]->alias) {
5388
6
      continue;
5389
6
    }
5390
2
    zend_string *class_name = cur_ref->class_name;
5391
5392
2
    if (!class_name) {
5393
0
      zend_string *lcname = zend_string_tolower(cur_ref->method_name);
5394
5395
0
      for (uint32_t j = 0; j < ce->num_traits; j++) {
5396
0
        const zend_class_entry *trait =
5397
0
          zend_hash_find_ptr(CG(class_table), ce->trait_names[j].lc_name);
5398
0
        ZEND_ASSERT(trait && "Trait must exist");
5399
0
        if (zend_hash_exists(&trait->function_table, lcname)) {
5400
0
          class_name = trait->name;
5401
0
          break;
5402
0
        }
5403
0
      }
5404
0
      zend_string_release_ex(lcname, false);
5405
0
      ZEND_ASSERT(class_name != NULL);
5406
0
    }
5407
5408
2
    zend_string *mname = zend_string_alloc(ZSTR_LEN(class_name) + ZSTR_LEN(cur_ref->method_name) + 2, false);
5409
2
    snprintf(ZSTR_VAL(mname), ZSTR_LEN(mname) + 1, "%s::%s", ZSTR_VAL(class_name), ZSTR_VAL(cur_ref->method_name));
5410
2
    add_assoc_str_ex(return_value, ZSTR_VAL(ce->trait_aliases[i]->alias), ZSTR_LEN(ce->trait_aliases[i]->alias), mname);
5411
2
  }
5412
8
}
5413
/* }}} */
5414
5415
/* {{{ Returns the class' parent class, or, if none exists, FALSE */
5416
ZEND_METHOD(ReflectionClass, getParentClass)
5417
2
{
5418
2
  const reflection_object *intern;
5419
2
  const zend_class_entry *ce;
5420
5421
2
  ZEND_PARSE_PARAMETERS_NONE();
5422
2
  GET_REFLECTION_OBJECT_PTR(ce);
5423
5424
2
  if (ce->parent) {
5425
1
    zend_reflection_class_factory(ce->parent, return_value);
5426
1
  } else {
5427
1
    RETURN_FALSE;
5428
1
  }
5429
2
}
5430
/* }}} */
5431
5432
/* {{{ Returns whether this class is a subclass of another class */
5433
ZEND_METHOD(ReflectionClass, isSubclassOf)
5434
3
{
5435
3
  const reflection_object *intern;
5436
3
  zend_class_entry *ce, *class_ce;
5437
3
  zend_string *class_str;
5438
3
  zend_object *class_obj;
5439
5440
9
  ZEND_PARSE_PARAMETERS_START(1, 1)
5441
15
    Z_PARAM_OBJ_OF_CLASS_OR_STR(class_obj, reflection_class_ptr, class_str)
5442
15
  ZEND_PARSE_PARAMETERS_END();
5443
5444
3
  if (class_obj) {
5445
1
    const reflection_object *argument = reflection_object_from_obj(class_obj);
5446
1
    if (argument->ptr == NULL) {
5447
0
      zend_throw_error(NULL, "Internal error: Failed to retrieve the argument's reflection object");
5448
0
      RETURN_THROWS();
5449
0
    }
5450
5451
1
    class_ce = argument->ptr;
5452
2
  } else {
5453
2
    if ((class_ce = zend_lookup_class(class_str)) == NULL) {
5454
2
      zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%pS\" does not exist", class_str);
5455
2
      RETURN_THROWS();
5456
2
    }
5457
2
  }
5458
5459
1
  GET_REFLECTION_OBJECT_PTR(ce);
5460
5461
1
  RETURN_BOOL(ce != class_ce && instanceof_function(ce, class_ce));
5462
1
}
5463
/* }}} */
5464
5465
/* {{{ Returns whether this class is a subclass of another class */
5466
ZEND_METHOD(ReflectionClass, implementsInterface)
5467
2
{
5468
2
  const reflection_object *intern;
5469
2
  zend_string *interface_str;
5470
2
  zend_class_entry *ce, *interface_ce;
5471
2
  zend_object *interface_obj;
5472
5473
6
  ZEND_PARSE_PARAMETERS_START(1, 1)
5474
10
    Z_PARAM_OBJ_OF_CLASS_OR_STR(interface_obj, reflection_class_ptr, interface_str)
5475
10
  ZEND_PARSE_PARAMETERS_END();
5476
5477
2
  if (interface_obj) {
5478
0
    const reflection_object *argument = reflection_object_from_obj(interface_obj);
5479
0
    if (argument->ptr == NULL) {
5480
0
      zend_throw_error(NULL, "Internal error: Failed to retrieve the argument's reflection object");
5481
0
      RETURN_THROWS();
5482
0
    }
5483
5484
0
    interface_ce = argument->ptr;
5485
2
  } else if ((interface_ce = zend_lookup_class(interface_str)) == NULL) {
5486
1
    zend_throw_exception_ex(reflection_exception_ptr, 0, "Interface \"%pS\" does not exist", interface_str);
5487
1
    RETURN_THROWS();
5488
1
  }
5489
5490
1
  if (!(interface_ce->ce_flags & ZEND_ACC_INTERFACE)) {
5491
1
    zend_throw_exception_ex(reflection_exception_ptr, 0, "%pS is not an interface", interface_ce->name);
5492
1
    RETURN_THROWS();
5493
1
  }
5494
5495
0
  GET_REFLECTION_OBJECT_PTR(ce);
5496
5497
0
  RETURN_BOOL(instanceof_function(ce, interface_ce));
5498
0
}
5499
/* }}} */
5500
5501
/* {{{ Returns whether this class is iterable (can be used inside foreach) */
5502
ZEND_METHOD(ReflectionClass, isIterable)
5503
8
{
5504
8
  const reflection_object *intern;
5505
8
  const zend_class_entry *ce;
5506
5507
8
  ZEND_PARSE_PARAMETERS_NONE();
5508
5509
8
  GET_REFLECTION_OBJECT_PTR(ce);
5510
5511
8
  if (ce->ce_flags & (ZEND_ACC_INTERFACE | ZEND_ACC_IMPLICIT_ABSTRACT_CLASS |
5512
8
                      ZEND_ACC_TRAIT     | ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) {
5513
6
    RETURN_FALSE;
5514
6
  }
5515
5516
2
  RETURN_BOOL((ce->get_iterator && ce->get_iterator != zend_hooked_object_get_iterator)
5517
2
        || instanceof_function(ce, zend_ce_traversable));
5518
2
}
5519
/* }}} */
5520
5521
/* {{{ Returns NULL or the extension the class belongs to */
5522
ZEND_METHOD(ReflectionClass, getExtension)
5523
1
{
5524
1
  const reflection_object *intern;
5525
1
  const zend_class_entry *ce;
5526
5527
1
  ZEND_PARSE_PARAMETERS_NONE();
5528
5529
1
  GET_REFLECTION_OBJECT_PTR(ce);
5530
5531
1
  if ((ce->type == ZEND_INTERNAL_CLASS) && ce->info.internal.module) {
5532
0
    reflection_extension_factory(return_value, ce->info.internal.module);
5533
0
  }
5534
1
}
5535
/* }}} */
5536
5537
/* {{{ Returns false or the name of the extension the class belongs to */
5538
ZEND_METHOD(ReflectionClass, getExtensionName)
5539
1
{
5540
1
  const reflection_object *intern;
5541
1
  const zend_class_entry *ce;
5542
5543
1
  ZEND_PARSE_PARAMETERS_NONE();
5544
5545
1
  GET_REFLECTION_OBJECT_PTR(ce);
5546
5547
1
  if ((ce->type == ZEND_INTERNAL_CLASS) && ce->info.internal.module) {
5548
0
    RETURN_STRING(ce->info.internal.module->name);
5549
1
  } else {
5550
1
    RETURN_FALSE;
5551
1
  }
5552
1
}
5553
/* }}} */
5554
5555
/* {{{ Returns whether this class is defined in namespace */
5556
ZEND_METHOD(ReflectionClass, inNamespace)
5557
1
{
5558
1
  const reflection_object *intern;
5559
1
  const zend_class_entry *ce;
5560
5561
1
  ZEND_PARSE_PARAMETERS_NONE();
5562
5563
1
  GET_REFLECTION_OBJECT_PTR(ce);
5564
5565
1
  const zend_string *name = ce->name;
5566
1
  const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
5567
1
  RETURN_BOOL(backslash);
5568
1
}
5569
/* }}} */
5570
5571
/* {{{ Returns the name of namespace where this class is defined */
5572
ZEND_METHOD(ReflectionClass, getNamespaceName)
5573
1
{
5574
1
  const reflection_object *intern;
5575
1
  const zend_class_entry *ce;
5576
5577
1
  ZEND_PARSE_PARAMETERS_NONE();
5578
5579
1
  GET_REFLECTION_OBJECT_PTR(ce);
5580
5581
1
  const zend_string *name = ce->name;
5582
1
  const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
5583
1
  if (backslash) {
5584
0
    RETURN_STRINGL(ZSTR_VAL(name), backslash - ZSTR_VAL(name));
5585
0
  }
5586
1
  RETURN_EMPTY_STRING();
5587
1
}
5588
/* }}} */
5589
5590
/* {{{ Returns the short name of the class (without namespace part) */
5591
ZEND_METHOD(ReflectionClass, getShortName)
5592
2
{
5593
2
  const reflection_object *intern;
5594
2
  const zend_class_entry *ce;
5595
5596
2
  ZEND_PARSE_PARAMETERS_NONE();
5597
5598
2
  GET_REFLECTION_OBJECT_PTR(ce);
5599
5600
2
  zend_string *name = ce->name;
5601
2
  const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
5602
2
  if (backslash) {
5603
0
    RETURN_STRINGL(backslash + 1, ZSTR_LEN(name) - (backslash - ZSTR_VAL(name) + 1));
5604
0
  }
5605
2
  RETURN_STR_COPY(name);
5606
2
}
5607
/* }}} */
5608
5609
/* {{{ Constructor. Takes an instance as an argument */
5610
ZEND_METHOD(ReflectionObject, __construct)
5611
110
{
5612
110
  reflection_class_object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
5613
110
}
5614
/* }}} */
5615
5616
/* {{{ Constructor. Throws an Exception in case the given property does not exist */
5617
ZEND_METHOD(ReflectionProperty, __construct)
5618
689
{
5619
689
  zend_string *classname_str;
5620
689
  zend_object *classname_obj;
5621
689
  zend_string *name;
5622
689
  zend_class_entry *ce;
5623
5624
2.06k
  ZEND_PARSE_PARAMETERS_START(2, 2)
5625
3.41k
    Z_PARAM_OBJ_OR_STR(classname_obj, classname_str)
5626
3.41k
    Z_PARAM_STR(name)
5627
689
  ZEND_PARSE_PARAMETERS_END();
5628
5629
683
  zval *object = ZEND_THIS;
5630
683
  reflection_object *intern = Z_REFLECTION_P(object);
5631
5632
683
  if (classname_obj) {
5633
208
    ce = classname_obj->ce;
5634
475
  } else if ((ce = zend_lookup_class(classname_str)) == NULL) {
5635
14
    zend_throw_exception_ex(reflection_exception_ptr, 0, "Class \"%pS\" does not exist", classname_str);
5636
14
    RETURN_THROWS();
5637
14
  }
5638
5639
669
  zend_property_info *property_info = zend_hash_find_ptr(&ce->properties_info, name);
5640
669
  bool dynam_prop = false;
5641
669
  if (property_info == NULL
5642
514
    || ((property_info->flags & ZEND_ACC_PRIVATE)
5643
80
      && property_info->ce != ce)
5644
669
  ) {
5645
    /* Check for dynamic properties */
5646
159
    if (property_info == NULL && classname_obj
5647
149
      && zend_hash_exists(classname_obj->handlers->get_properties(classname_obj), name)
5648
159
    ) {
5649
142
      dynam_prop = true;
5650
142
    }
5651
159
    if (!dynam_prop) {
5652
17
      zend_throw_exception_ex(reflection_exception_ptr, 0, "Property %pS::$%pS does not exist", ce->name, name);
5653
17
      RETURN_THROWS();
5654
17
    }
5655
159
  }
5656
5657
652
  zval *prop_name = reflection_prop_name(object);
5658
652
  zval_ptr_dtor(prop_name);
5659
652
  ZVAL_STR_COPY(prop_name, name);
5660
  /* Note: class name are always interned, no need to destroy them */
5661
652
  if (!dynam_prop) {
5662
510
    ZVAL_STR_COPY(reflection_prop_class(object), property_info->ce->name);
5663
510
  } else {
5664
142
    ZVAL_STR_COPY(reflection_prop_class(object), ce->name);
5665
142
  }
5666
5667
652
  if (intern->ptr) {
5668
1
    reflection_free_property_reference(intern->ptr);
5669
1
  }
5670
5671
652
  property_reference *reference = (property_reference*) emalloc(sizeof(property_reference));
5672
652
  reference->prop = dynam_prop ? NULL : property_info;
5673
652
  reference->unmangled_name = zend_string_copy(name);
5674
652
  memset(reference->cache_slot, 0, sizeof(reference->cache_slot));
5675
652
  intern->ptr = reference;
5676
652
  intern->ref_type = REF_TYPE_PROPERTY;
5677
652
  intern->ce = ce;
5678
652
}
5679
/* }}} */
5680
5681
/* {{{ Returns a string representation */
5682
ZEND_METHOD(ReflectionProperty, __toString)
5683
35
{
5684
35
  const reflection_object *intern;
5685
35
  const property_reference *ref;
5686
35
  smart_str str = {0};
5687
5688
35
  ZEND_PARSE_PARAMETERS_NONE();
5689
35
  GET_REFLECTION_OBJECT_PTR(ref);
5690
35
  _property_string(&str, ref->prop, ref->unmangled_name, "");
5691
35
  RETURN_STR(smart_str_extract(&str));
5692
35
}
5693
/* }}} */
5694
5695
/* {{{ Returns the property's name */
5696
ZEND_METHOD(ReflectionProperty, getName)
5697
8
{
5698
8
  const reflection_object *intern;
5699
8
  const property_reference *ref;
5700
5701
8
  ZEND_PARSE_PARAMETERS_NONE();
5702
5703
8
  GET_REFLECTION_OBJECT_PTR(ref);
5704
8
  RETURN_STR_COPY(ref->unmangled_name);
5705
8
}
5706
/* }}} */
5707
5708
ZEND_METHOD(ReflectionProperty, getMangledName)
5709
0
{
5710
0
  const reflection_object *intern;
5711
0
  const property_reference *ref;
5712
5713
0
  ZEND_PARSE_PARAMETERS_NONE();
5714
5715
0
  GET_REFLECTION_OBJECT_PTR(ref);
5716
0
  if (ref->prop == NULL) {
5717
0
    RETURN_STR_COPY(ref->unmangled_name);
5718
0
  }
5719
5720
0
  RETURN_STR_COPY(ref->prop->name);
5721
0
}
5722
5723
static void _property_check_flag(INTERNAL_FUNCTION_PARAMETERS, int mask) /* {{{ */
5724
59
{
5725
59
  const reflection_object *intern;
5726
59
  const property_reference *ref;
5727
5728
59
  ZEND_PARSE_PARAMETERS_NONE();
5729
59
  GET_REFLECTION_OBJECT_PTR(ref);
5730
59
  RETURN_BOOL(prop_get_flags(ref) & mask);
5731
59
}
5732
/* }}} */
5733
5734
/* {{{ Returns whether this property is public */
5735
ZEND_METHOD(ReflectionProperty, isPublic)
5736
0
{
5737
0
  _property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PUBLIC);
5738
0
}
5739
/* }}} */
5740
5741
/* {{{ Returns whether this property is private */
5742
ZEND_METHOD(ReflectionProperty, isPrivate)
5743
0
{
5744
0
  _property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PRIVATE);
5745
0
}
5746
/* }}} */
5747
5748
/* {{{ Returns whether this property is protected */
5749
ZEND_METHOD(ReflectionProperty, isProtected)
5750
0
{
5751
0
  _property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PROTECTED);
5752
0
}
5753
/* }}} */
5754
5755
ZEND_METHOD(ReflectionProperty, isPrivateSet)
5756
0
{
5757
0
  _property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PRIVATE_SET);
5758
0
}
5759
5760
ZEND_METHOD(ReflectionProperty, isProtectedSet)
5761
0
{
5762
0
  _property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PROTECTED_SET);
5763
0
}
5764
5765
/* {{{ Returns whether this property is static */
5766
ZEND_METHOD(ReflectionProperty, isStatic)
5767
0
{
5768
0
  _property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_STATIC);
5769
0
}
5770
/* }}} */
5771
5772
ZEND_METHOD(ReflectionProperty, isReadOnly)
5773
0
{
5774
0
  _property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_READONLY);
5775
0
}
5776
5777
ZEND_METHOD(ReflectionProperty, isAbstract)
5778
0
{
5779
0
  _property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_ABSTRACT);
5780
0
}
5781
5782
ZEND_METHOD(ReflectionProperty, isVirtual)
5783
56
{
5784
56
  _property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_VIRTUAL);
5785
56
}
5786
5787
static void _property_check_dynamic(INTERNAL_FUNCTION_PARAMETERS, bool dynamic_true)
5788
0
{
5789
0
  const reflection_object *intern;
5790
0
  const property_reference *ref;
5791
5792
0
  ZEND_PARSE_PARAMETERS_NONE();
5793
0
  GET_REFLECTION_OBJECT_PTR(ref);
5794
0
  bool is_dynamic = ref->prop == NULL;
5795
0
  RETURN_BOOL(dynamic_true ? is_dynamic : !is_dynamic);
5796
0
}
5797
5798
/* {{{ Returns whether this property is default (declared at compilation time). */
5799
ZEND_METHOD(ReflectionProperty, isDefault)
5800
0
{
5801
0
  _property_check_dynamic(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
5802
0
}
5803
/* }}} */
5804
5805
/* {{{ Returns whether this property is dynamic (not declared at compilation time). */
5806
ZEND_METHOD(ReflectionProperty, isDynamic)
5807
0
{
5808
0
  _property_check_dynamic(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
5809
0
}
5810
/* }}} */
5811
5812
/* {{{ Returns whether this property has been promoted from a constructor */
5813
ZEND_METHOD(ReflectionProperty, isPromoted)
5814
0
{
5815
0
  _property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_PROMOTED);
5816
0
}
5817
/* }}} */
5818
5819
/* {{{ Returns a bitfield of the modifiers for this property */
5820
ZEND_METHOD(ReflectionProperty, getModifiers)
5821
76
{
5822
76
  const reflection_object *intern;
5823
76
  const property_reference *ref;
5824
76
  uint32_t keep_flags = ZEND_ACC_PPP_MASK | ZEND_ACC_PPP_SET_MASK | ZEND_ACC_STATIC | ZEND_ACC_READONLY | ZEND_ACC_ABSTRACT | ZEND_ACC_VIRTUAL | ZEND_ACC_FINAL;
5825
5826
76
  ZEND_PARSE_PARAMETERS_NONE();
5827
76
  GET_REFLECTION_OBJECT_PTR(ref);
5828
5829
76
  RETURN_LONG(prop_get_flags(ref) & keep_flags);
5830
76
}
5831
/* }}} */
5832
5833
/* {{{ Returns this property's value */
5834
ZEND_METHOD(ReflectionProperty, getValue)
5835
98
{
5836
98
  const reflection_object *intern;
5837
98
  property_reference *ref;
5838
98
  zval *object = NULL;
5839
5840
294
  ZEND_PARSE_PARAMETERS_START(0, 1)
5841
294
    Z_PARAM_OPTIONAL
5842
358
    Z_PARAM_OBJECT_EX(object, 1, 0)
5843
98
  ZEND_PARSE_PARAMETERS_END();
5844
5845
98
  GET_REFLECTION_OBJECT_PTR(ref);
5846
5847
98
  if (prop_get_flags(ref) & ZEND_ACC_STATIC) {
5848
18
    zval *member_p = zend_read_static_property_ex(intern->ce, ref->unmangled_name, false);
5849
18
    if (member_p) {
5850
8
      RETURN_COPY_DEREF(member_p);
5851
8
    }
5852
10
    return;
5853
18
  }
5854
80
  if (!object) {
5855
0
    zend_argument_type_error(1, "must be provided for instance properties");
5856
0
    RETURN_THROWS();
5857
0
  }
5858
5859
  /* TODO: Should this always use intern->ce? */
5860
80
  if (!instanceof_function(Z_OBJCE_P(object), ref->prop ? ref->prop->ce : intern->ce)) {
5861
0
    zend_throw_exception(reflection_exception_ptr, "Given object is not an instance of the class this property was declared in", 0);
5862
0
    RETURN_THROWS();
5863
0
  }
5864
5865
80
  if (ref->cache_slot[0] == Z_OBJCE_P(object)) {
5866
51
    uintptr_t prop_offset = (uintptr_t) ref->cache_slot[1];
5867
5868
51
    if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) {
5869
51
      zval *retval = OBJ_PROP(Z_OBJ_P(object), prop_offset);
5870
51
      if (EXPECTED(!Z_ISUNDEF_P(retval))) {
5871
51
        RETURN_COPY_DEREF(retval);
5872
51
      }
5873
51
    }
5874
51
  }
5875
5876
29
  zval rv;
5877
29
  const zend_class_entry *old_scope = EG(fake_scope);
5878
29
  EG(fake_scope) = intern->ce;
5879
29
  zval *member_p = Z_OBJ_P(object)->handlers->read_property(Z_OBJ_P(object),
5880
29
      ref->unmangled_name, BP_VAR_R, ref->cache_slot, &rv);
5881
29
  EG(fake_scope) = old_scope;
5882
5883
29
  if (member_p != &rv) {
5884
29
    RETURN_COPY_DEREF(member_p);
5885
29
  } else {
5886
0
    if (Z_ISREF_P(member_p)) {
5887
0
      zend_unwrap_reference(member_p);
5888
0
    }
5889
0
    RETURN_COPY_VALUE(member_p);
5890
0
  }
5891
29
}
5892
/* }}} */
5893
5894
/* {{{ Sets this property's value */
5895
ZEND_METHOD(ReflectionProperty, setValue)
5896
82
{
5897
82
  const reflection_object *intern;
5898
82
  property_reference *ref;
5899
82
  zval *value;
5900
5901
82
  GET_REFLECTION_OBJECT_PTR(ref);
5902
5903
82
  if (prop_get_flags(ref) & ZEND_ACC_STATIC) {
5904
12
    if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(), "z", &value) == FAILURE) {
5905
11
      zval *tmp;
5906
11
      if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &tmp, &value) == FAILURE) {
5907
0
        RETURN_THROWS();
5908
0
      }
5909
5910
11
      if (Z_TYPE_P(tmp) != IS_NULL && Z_TYPE_P(tmp) != IS_OBJECT) {
5911
0
        zend_string *method_name = get_active_function_or_method_name();
5912
0
        zend_error(E_DEPRECATED, "Calling %pS() with a 1st argument which is not null or an object is deprecated", method_name);
5913
0
        zend_string_release(method_name);
5914
0
        if (UNEXPECTED(EG(exception))) {
5915
0
          RETURN_THROWS();
5916
0
        }
5917
0
      }
5918
11
    } else {
5919
1
      zend_string *method_name = get_active_function_or_method_name();
5920
1
      zend_error(E_DEPRECATED, "Calling %pS() with a single argument is deprecated", method_name);
5921
1
      zend_string_release(method_name);
5922
1
      if (UNEXPECTED(EG(exception))) {
5923
0
        RETURN_THROWS();
5924
0
      }
5925
1
    }
5926
5927
12
    zend_update_static_property_ex(intern->ce, ref->unmangled_name, value);
5928
70
  } else {
5929
70
    zend_object *object;
5930
210
    ZEND_PARSE_PARAMETERS_START(2, 2)
5931
280
      Z_PARAM_OBJ(object)
5932
340
      Z_PARAM_ZVAL(value)
5933
340
    ZEND_PARSE_PARAMETERS_END();
5934
5935
68
    if (!instanceof_function(object->ce, intern->ce)) {
5936
0
      zend_string *method_name = get_active_function_or_method_name();
5937
0
      zend_error(E_DEPRECATED, "Calling %pS() with a given object that is not an instance of the class this property was declared in is deprecated", method_name);
5938
0
      zend_string_release(method_name);
5939
0
      if (UNEXPECTED(EG(exception))) {
5940
0
        RETURN_THROWS();
5941
0
      }
5942
0
    }
5943
5944
68
    const zend_class_entry *old_scope = EG(fake_scope);
5945
68
    EG(fake_scope) = intern->ce;
5946
68
    object->handlers->write_property(object, ref->unmangled_name, value, ref->cache_slot);
5947
68
    EG(fake_scope) = old_scope;
5948
68
  }
5949
82
}
5950
/* }}} */
5951
5952
/* Return the property info being used when accessing 'ref->prop' from scope
5953
 * 'scope' on 'object'. The result may be different from 'ref->prop' when the
5954
 * property is overridden on 'object' and was not private in 'scope'.
5955
 * The effective prop may add hooks or change flags. */
5956
static zend_property_info *reflection_property_get_effective_prop(
5957
    zend_property_info *prop, zend_string *unmangled_name,
5958
1.60k
    const zend_class_entry *scope, const zend_object *object) {
5959
1.60k
  if (scope != object->ce && !(prop && (prop->flags & ZEND_ACC_PRIVATE))) {
5960
50
    prop = zend_hash_find_ptr(&object->ce->properties_info, unmangled_name);
5961
50
  }
5962
1.60k
  return prop;
5963
1.60k
}
5964
5965
ZEND_METHOD(ReflectionProperty, getRawValue)
5966
2
{
5967
2
  const reflection_object *intern;
5968
2
  property_reference *ref;
5969
2
  zval *object;
5970
5971
6
  ZEND_PARSE_PARAMETERS_START(1, 1)
5972
8
    Z_PARAM_OBJECT(object)
5973
2
  ZEND_PARSE_PARAMETERS_END();
5974
5975
1
  GET_REFLECTION_OBJECT_PTR(ref);
5976
5977
1
  if (!instanceof_function(Z_OBJCE_P(object), intern->ce)) {
5978
0
    zend_throw_exception(reflection_exception_ptr, "Given object is not an instance of the class this property was declared in", 0);
5979
0
    RETURN_THROWS();
5980
0
  }
5981
5982
1
  if (ref->cache_slot[0] == Z_OBJCE_P(object)) {
5983
0
    uintptr_t prop_offset = (uintptr_t) ref->cache_slot[1];
5984
5985
0
    if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) {
5986
0
      zval *retval = OBJ_PROP(Z_OBJ_P(object), prop_offset);
5987
0
      if (EXPECTED(!Z_ISUNDEF_P(retval))) {
5988
0
        RETURN_COPY_DEREF(retval);
5989
0
      }
5990
0
    }
5991
0
  }
5992
5993
1
  const zend_property_info *prop = reflection_property_get_effective_prop(ref->prop,
5994
1
      ref->unmangled_name, intern->ce, Z_OBJ_P(object));
5995
5996
1
  if (UNEXPECTED(prop && (prop->flags & ZEND_ACC_STATIC))) {
5997
0
    zend_throw_exception(reflection_exception_ptr, "May not use getRawValue on static properties", 0);
5998
0
    RETURN_THROWS();
5999
0
  }
6000
6001
1
  if (!prop || !prop->hooks || !prop->hooks[ZEND_PROPERTY_HOOK_GET]) {
6002
1
    zval rv;
6003
1
    const zend_class_entry *old_scope = EG(fake_scope);
6004
1
    EG(fake_scope) = intern->ce;
6005
1
    zval *member_p = Z_OBJ_P(object)->handlers->read_property(
6006
1
        Z_OBJ_P(object), ref->unmangled_name, BP_VAR_R,
6007
1
        ref->cache_slot, &rv);
6008
1
    EG(fake_scope) = old_scope;
6009
6010
1
    if (member_p != &rv) {
6011
1
      RETURN_COPY_DEREF(member_p);
6012
1
    } else {
6013
0
      if (Z_ISREF_P(member_p)) {
6014
0
        zend_unwrap_reference(member_p);
6015
0
      }
6016
0
      RETURN_COPY_VALUE(member_p);
6017
0
    }
6018
1
  } else {
6019
0
    zend_function *func = zend_get_property_hook_trampoline(prop, ZEND_PROPERTY_HOOK_GET, ref->unmangled_name);
6020
0
    zend_call_known_instance_method_with_0_params(func, Z_OBJ_P(object), return_value);
6021
0
  }
6022
1
}
6023
6024
static void zend_reflection_property_set_raw_value_ex(zend_property_info *prop,
6025
    zend_string *unmangled_name, void *cache_slot[3],
6026
    const zend_class_entry *scope, zend_object *object, zval *value)
6027
657
{
6028
657
  ZEND_ASSERT(!prop || !(prop->flags & ZEND_ACC_STATIC));
6029
6030
657
  if (!prop || !prop->hooks || !prop->hooks[ZEND_PROPERTY_HOOK_SET]) {
6031
645
    const zend_class_entry *old_scope = EG(fake_scope);
6032
645
    EG(fake_scope) = scope;
6033
645
    object->handlers->write_property(object, unmangled_name, value, cache_slot);
6034
645
    EG(fake_scope) = old_scope;
6035
645
  } else {
6036
12
    zend_function *func = zend_get_property_hook_trampoline(prop, ZEND_PROPERTY_HOOK_SET, unmangled_name);
6037
12
    zend_call_known_instance_method_with_1_params(func, object, NULL, value);
6038
12
  }
6039
657
}
6040
6041
PHPAPI void zend_reflection_property_set_raw_value(zend_property_info *prop,
6042
    zend_string *unmangled_name, void *cache_slot[3],
6043
    const zend_class_entry *scope, zend_object *object, zval *value)
6044
1
{
6045
1
  prop = reflection_property_get_effective_prop(prop,
6046
1
      unmangled_name, scope, object);
6047
6048
1
  if (UNEXPECTED(prop && (prop->flags & ZEND_ACC_STATIC))) {
6049
0
    zend_throw_exception(reflection_exception_ptr, "May not use setRawValue on static properties", 0);
6050
0
    return;
6051
0
  }
6052
6053
1
  zend_reflection_property_set_raw_value_ex(prop, unmangled_name, cache_slot,
6054
1
      scope, object, value);
6055
1
}
6056
6057
ZEND_METHOD(ReflectionProperty, setRawValue)
6058
1
{
6059
1
  const reflection_object *intern;
6060
1
  property_reference *ref;
6061
1
  zval *object;
6062
1
  zval *value;
6063
6064
1
  GET_REFLECTION_OBJECT_PTR(ref);
6065
6066
3
  ZEND_PARSE_PARAMETERS_START(2, 2) {
6067
4
    Z_PARAM_OBJECT(object)
6068
5
    Z_PARAM_ZVAL(value)
6069
5
  } ZEND_PARSE_PARAMETERS_END();
6070
6071
1
  if (!instanceof_function(Z_OBJCE_P(object), intern->ce)) {
6072
0
    zend_string *method_name = get_active_function_or_method_name();
6073
0
    zend_error(E_DEPRECATED, "Calling %pS() with a given object that is not an instance of the class this property was declared in is deprecated", method_name);
6074
0
    zend_string_release(method_name);
6075
0
    if (UNEXPECTED(EG(exception))) {
6076
0
      RETURN_THROWS();
6077
0
    }
6078
0
  }
6079
6080
1
  zend_reflection_property_set_raw_value(ref->prop, ref->unmangled_name,
6081
1
      ref->cache_slot, intern->ce, Z_OBJ_P(object), value);
6082
1
}
6083
6084
static zend_result reflection_property_check_lazy_compatible(
6085
    const zend_property_info *prop, zend_string *unmangled_name,
6086
    const zend_class_entry *scope, const zend_object *object, const char *method)
6087
1.03k
{
6088
1.03k
  if (!prop) {
6089
31
    zend_throw_exception_ex(reflection_exception_ptr, 0,
6090
31
        "Cannot use %s() on dynamic property %pS::$%pS",
6091
31
        method, scope->name,
6092
31
        unmangled_name);
6093
31
    return FAILURE;
6094
31
  }
6095
6096
1.00k
  if (prop->flags & ZEND_ACC_STATIC) {
6097
0
    zend_throw_exception_ex(reflection_exception_ptr, 0,
6098
0
        "Cannot use %s() on static property %pS::$%pS",
6099
0
        method, prop->ce->name,
6100
0
        unmangled_name);
6101
0
    return FAILURE;
6102
0
  }
6103
6104
1.00k
  if (prop->flags & ZEND_ACC_VIRTUAL) {
6105
0
    zend_throw_exception_ex(reflection_exception_ptr, 0,
6106
0
        "Cannot use %s() on virtual property %pS::$%pS",
6107
0
        method, prop->ce->name,
6108
0
        unmangled_name);
6109
0
    return FAILURE;
6110
0
  }
6111
6112
1.00k
  if (UNEXPECTED(object->handlers->write_property != zend_std_write_property)
6113
0
    && !zend_class_can_be_lazy(object->ce)
6114
1.00k
  ) {
6115
0
    zend_throw_exception_ex(reflection_exception_ptr, 0,
6116
0
        "Cannot use %s() on internal class %pS",
6117
0
        method, object->ce->name);
6118
0
    return FAILURE;
6119
0
  }
6120
6121
1.00k
  ZEND_ASSERT(IS_VALID_PROPERTY_OFFSET(prop->offset));
6122
6123
1.00k
  return SUCCESS;
6124
1.00k
}
6125
6126
PHPAPI void zend_reflection_property_set_raw_value_without_lazy_initialization(
6127
    zend_property_info *prop, zend_string *unmangled_name,
6128
    void *cache_slot[3], const zend_class_entry *scope,
6129
    zend_object *object, zval *value)
6130
667
{
6131
689
  while (zend_object_is_lazy_proxy(object)
6132
211
      && zend_lazy_object_initialized(object)) {
6133
22
    object = zend_lazy_object_get_instance(object);
6134
22
  }
6135
6136
667
  prop = reflection_property_get_effective_prop(prop,
6137
667
      unmangled_name, scope, object);
6138
6139
667
  if (reflection_property_check_lazy_compatible(prop, unmangled_name,
6140
667
        scope, object, "setRawValueWithoutLazyInitialization") == FAILURE) {
6141
11
    ZEND_ASSERT(EG(exception));
6142
11
    return;
6143
11
  }
6144
6145
656
  zval *var_ptr = OBJ_PROP(object, prop->offset);
6146
656
  bool prop_was_lazy = Z_PROP_FLAG_P(var_ptr) & IS_PROP_LAZY;
6147
6148
  /* Do not trigger initialization */
6149
656
  Z_PROP_FLAG_P(var_ptr) &= ~IS_PROP_LAZY;
6150
6151
656
  zend_reflection_property_set_raw_value_ex(prop, unmangled_name,
6152
656
      cache_slot, scope, object, value);
6153
6154
  /* Mark property as lazy again if an exception prevented update */
6155
656
  if (EG(exception) && prop_was_lazy && Z_TYPE_P(var_ptr) == IS_UNDEF
6156
17
      && zend_object_is_lazy(object)
6157
17
      && !zend_lazy_object_initialized(object)) {
6158
17
    Z_PROP_FLAG_P(var_ptr) |= IS_PROP_LAZY;
6159
17
  }
6160
6161
  /* Object becomes non-lazy if this was the last lazy prop */
6162
656
  if (prop_was_lazy && !(Z_PROP_FLAG_P(var_ptr) & IS_PROP_LAZY)
6163
517
    && zend_object_is_lazy(object)
6164
512
    && !zend_lazy_object_initialized(object)
6165
512
    && zend_lazy_object_decr_lazy_props(object)
6166
656
  ) {
6167
258
    zend_lazy_object_realize(object);
6168
258
  }
6169
656
}
6170
6171
/* {{{ Set property value without triggering initializer while skipping hooks if any */
6172
ZEND_METHOD(ReflectionProperty, setRawValueWithoutLazyInitialization)
6173
674
{
6174
674
  const reflection_object *intern;
6175
674
  property_reference *ref;
6176
674
  zend_object *object;
6177
674
  zval *value;
6178
6179
674
  GET_REFLECTION_OBJECT_PTR(ref);
6180
6181
2.01k
  ZEND_PARSE_PARAMETERS_START(2, 2) {
6182
2.68k
    Z_PARAM_OBJ_OF_CLASS(object, intern->ce)
6183
3.33k
    Z_PARAM_ZVAL(value)
6184
3.33k
  } ZEND_PARSE_PARAMETERS_END();
6185
6186
667
  zend_reflection_property_set_raw_value_without_lazy_initialization(
6187
667
      ref->prop, ref->unmangled_name, ref->cache_slot, intern->ce,
6188
667
      object, value);
6189
667
}
6190
6191
/* {{{ Mark property as non-lazy, and initialize to default value */
6192
ZEND_METHOD(ReflectionProperty, skipLazyInitialization)
6193
369
{
6194
369
  const reflection_object *intern;
6195
369
  property_reference *ref;
6196
369
  zend_object *object;
6197
6198
369
  GET_REFLECTION_OBJECT_PTR(ref);
6199
6200
1.10k
  ZEND_PARSE_PARAMETERS_START(1, 1) {
6201
1.47k
    Z_PARAM_OBJ_OF_CLASS(object, intern->ce)
6202
1.47k
  } ZEND_PARSE_PARAMETERS_END();
6203
6204
382
  while (zend_object_is_lazy_proxy(object)
6205
173
      && zend_lazy_object_initialized(object)) {
6206
18
    object = zend_lazy_object_get_instance(object);
6207
18
  }
6208
6209
364
  const zend_property_info *prop = reflection_property_get_effective_prop(ref->prop,
6210
364
      ref->unmangled_name, intern->ce, object);
6211
6212
364
  if (reflection_property_check_lazy_compatible(prop,
6213
364
        ref->unmangled_name, intern->ce, object,
6214
364
        "skipLazyInitialization") == FAILURE) {
6215
20
    RETURN_THROWS();
6216
20
  }
6217
6218
344
  const zval *src = &object->ce->default_properties_table[OBJ_PROP_TO_NUM(prop->offset)];
6219
344
  zval *dst = OBJ_PROP(object, prop->offset);
6220
6221
344
  if (!(Z_PROP_FLAG_P(dst) & IS_PROP_LAZY)) {
6222
    /* skipLazyInitialization has no effect on non-lazy properties */
6223
63
    return;
6224
63
  }
6225
6226
281
  ZEND_ASSERT(Z_TYPE_P(dst) == IS_UNDEF && "Lazy property should be UNDEF");
6227
6228
281
  ZVAL_COPY_PROP(dst, src);
6229
6230
  /* Object becomes non-lazy if this was the last lazy prop */
6231
281
  if (zend_object_is_lazy(object)
6232
281
    && !zend_lazy_object_initialized(object)
6233
281
    && zend_lazy_object_decr_lazy_props(object)
6234
281
  ) {
6235
65
    zend_lazy_object_realize(object);
6236
65
  }
6237
281
}
6238
6239
ZEND_METHOD(ReflectionProperty, isLazy)
6240
573
{
6241
573
  const reflection_object *intern;
6242
573
  const property_reference *ref;
6243
573
  zend_object *object;
6244
6245
573
  GET_REFLECTION_OBJECT_PTR(ref);
6246
6247
1.71k
  ZEND_PARSE_PARAMETERS_START(1, 1) {
6248
2.29k
    Z_PARAM_OBJ_OF_CLASS(object, intern->ce)
6249
2.29k
  } ZEND_PARSE_PARAMETERS_END();
6250
6251
806
  while (zend_object_is_lazy_proxy(object)
6252
430
      && zend_lazy_object_initialized(object)) {
6253
235
    object = zend_lazy_object_get_instance(object);
6254
235
  }
6255
6256
571
  const zend_property_info *prop = reflection_property_get_effective_prop(ref->prop,
6257
571
      ref->unmangled_name, intern->ce, object);
6258
6259
571
  if (!prop || prop->flags & (ZEND_ACC_STATIC | ZEND_ACC_VIRTUAL)) {
6260
325
    RETURN_FALSE;
6261
325
  }
6262
6263
246
  RETURN_BOOL(Z_PROP_FLAG_P(OBJ_PROP(object, prop->offset)) & IS_PROP_LAZY);
6264
246
}
6265
6266
/* {{{ Returns true if property was initialized */
6267
ZEND_METHOD(ReflectionProperty, isInitialized)
6268
0
{
6269
0
  const reflection_object *intern;
6270
0
  property_reference *ref;
6271
0
  zval *object = NULL;
6272
6273
0
  ZEND_PARSE_PARAMETERS_START(0, 1)
6274
0
    Z_PARAM_OPTIONAL
6275
0
    Z_PARAM_OBJECT_EX(object, 1, 0)
6276
0
  ZEND_PARSE_PARAMETERS_END();
6277
6278
0
  GET_REFLECTION_OBJECT_PTR(ref);
6279
6280
0
  if (prop_get_flags(ref) & ZEND_ACC_STATIC) {
6281
0
    const zval *member_p = zend_read_static_property_ex(intern->ce, ref->unmangled_name, true);
6282
0
    if (member_p) {
6283
0
      RETURN_BOOL(!Z_ISUNDEF_P(member_p));
6284
0
    }
6285
0
    RETURN_FALSE;
6286
0
  }
6287
0
  if (!object) {
6288
0
    zend_argument_type_error(1, "must be provided for instance properties");
6289
0
    RETURN_THROWS();
6290
0
  }
6291
6292
  /* TODO: Should this always use intern->ce? */
6293
0
  if (!instanceof_function(Z_OBJCE_P(object), ref->prop ? ref->prop->ce : intern->ce)) {
6294
0
    zend_throw_exception(reflection_exception_ptr, "Given object is not an instance of the class this property was declared in", 0);
6295
0
    RETURN_THROWS();
6296
0
  }
6297
6298
0
  if (ref->cache_slot[0] == Z_OBJCE_P(object)) {
6299
0
    uintptr_t prop_offset = (uintptr_t) ref->cache_slot[1];
6300
6301
0
    if (EXPECTED(IS_VALID_PROPERTY_OFFSET(prop_offset))) {
6302
0
      zval *value = OBJ_PROP(Z_OBJ_P(object), prop_offset);
6303
0
      RETURN_BOOL(!Z_ISUNDEF_P(value));
6304
0
    }
6305
0
  }
6306
6307
0
  const zend_class_entry *old_scope = EG(fake_scope);
6308
0
  EG(fake_scope) = intern->ce;
6309
0
  int retval = Z_OBJ_HT_P(object)->has_property(Z_OBJ_P(object),
6310
0
      ref->unmangled_name, ZEND_PROPERTY_EXISTS, ref->cache_slot);
6311
0
  EG(fake_scope) = old_scope;
6312
6313
0
  RETVAL_BOOL(retval);
6314
0
}
6315
/* }}} */
6316
6317
/* {{{ Get the declaring class */
6318
ZEND_METHOD(ReflectionProperty, getDeclaringClass)
6319
4
{
6320
4
  const reflection_object *intern;
6321
4
  const property_reference *ref;
6322
6323
4
  ZEND_PARSE_PARAMETERS_NONE();
6324
4
  GET_REFLECTION_OBJECT_PTR(ref);
6325
6326
4
  zend_class_entry *ce = ref->prop ? ref->prop->ce : intern->ce;
6327
4
  zend_reflection_class_factory(ce, return_value);
6328
4
}
6329
/* }}} */
6330
6331
/* {{{ Returns the doc comment for this property */
6332
ZEND_METHOD(ReflectionProperty, getDocComment)
6333
8
{
6334
8
  const reflection_object *intern;
6335
8
  const property_reference *ref;
6336
6337
8
  ZEND_PARSE_PARAMETERS_NONE();
6338
8
  GET_REFLECTION_OBJECT_PTR(ref);
6339
8
  if (ref->prop && ref->prop->doc_comment) {
6340
1
    RETURN_STR_COPY(ref->prop->doc_comment);
6341
1
  }
6342
7
  RETURN_FALSE;
6343
7
}
6344
/* }}} */
6345
6346
/* {{{ Returns the attributes of this property */
6347
ZEND_METHOD(ReflectionProperty, getAttributes)
6348
123
{
6349
123
  const reflection_object *intern;
6350
123
  const property_reference *ref;
6351
6352
123
  GET_REFLECTION_OBJECT_PTR(ref);
6353
6354
123
  if (ref->prop == NULL) {
6355
1
    RETURN_EMPTY_ARRAY();
6356
1
  }
6357
6358
122
  reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
6359
122
    ref->prop->attributes, 0, ref->prop->ce, ZEND_ATTRIBUTE_TARGET_PROPERTY,
6360
122
    ref->prop->ce->type == ZEND_USER_CLASS ? ref->prop->ce->info.user.filename : NULL);
6361
122
}
6362
/* }}} */
6363
6364
/* {{{ No-op; previously controlled whether non-public properties can be requested */
6365
ZEND_METHOD(ReflectionProperty, setAccessible)
6366
0
{
6367
0
  bool visible;
6368
6369
0
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "b", &visible) == FAILURE) {
6370
0
    RETURN_THROWS();
6371
0
  }
6372
0
}
6373
/* }}} */
6374
6375
/* {{{ Returns the type associated with the property */
6376
ZEND_METHOD(ReflectionProperty, getType)
6377
22
{
6378
22
  const reflection_object *intern;
6379
22
  const property_reference *ref;
6380
6381
22
  ZEND_PARSE_PARAMETERS_NONE();
6382
6383
22
  GET_REFLECTION_OBJECT_PTR(ref);
6384
6385
22
  if (!ref->prop || !ZEND_TYPE_IS_SET(ref->prop->type)) {
6386
1
    RETURN_NULL();
6387
1
  }
6388
6389
21
  reflection_type_factory(ref->prop->type, return_value, true);
6390
21
}
6391
/* }}} */
6392
6393
ZEND_METHOD(ReflectionProperty, getSettableType)
6394
0
{
6395
0
  const reflection_object *intern;
6396
0
  const property_reference *ref;
6397
6398
0
  ZEND_PARSE_PARAMETERS_NONE();
6399
6400
0
  GET_REFLECTION_OBJECT_PTR(ref);
6401
6402
0
  const zend_property_info *prop = ref->prop;
6403
  /* Dynamic property is untyped. */
6404
0
  if (!prop) {
6405
0
    RETURN_NULL();
6406
0
  }
6407
6408
  /* Get-only virtual property can never be written to. */
6409
0
  if (prop->hooks && (prop->flags & ZEND_ACC_VIRTUAL) && !prop->hooks[ZEND_PROPERTY_HOOK_SET]) {
6410
0
    zend_type never_type = ZEND_TYPE_INIT_CODE(IS_NEVER, false, 0);
6411
0
    reflection_type_factory(never_type, return_value, true);
6412
0
    return;
6413
0
  }
6414
6415
  /* Extract set $value parameter type. */
6416
0
  if (prop->hooks && prop->hooks[ZEND_PROPERTY_HOOK_SET]) {
6417
0
    const zend_arg_info *arg_info = &prop->hooks[ZEND_PROPERTY_HOOK_SET]->common.arg_info[0];
6418
0
    if (!ZEND_TYPE_IS_SET(arg_info->type)) {
6419
0
      RETURN_NULL();
6420
0
    }
6421
0
    reflection_type_factory(arg_info->type, return_value, true);
6422
0
    return;
6423
0
  }
6424
6425
  /* Fall back to property type */
6426
0
  if (!ZEND_TYPE_IS_SET(prop->type)) {
6427
0
    RETURN_NULL();
6428
0
  }
6429
0
  reflection_type_factory(prop->type, return_value, true);
6430
0
}
6431
6432
/* {{{ Returns whether property has a type */
6433
ZEND_METHOD(ReflectionProperty, hasType)
6434
0
{
6435
0
  const reflection_object *intern;
6436
0
  const property_reference *ref;
6437
6438
0
  ZEND_PARSE_PARAMETERS_NONE();
6439
6440
0
  GET_REFLECTION_OBJECT_PTR(ref);
6441
6442
0
  RETVAL_BOOL(ref->prop && ZEND_TYPE_IS_SET(ref->prop->type));
6443
0
}
6444
/* }}} */
6445
6446
/* {{{ Returns whether property has a default value */
6447
ZEND_METHOD(ReflectionProperty, hasDefaultValue)
6448
5
{
6449
5
  const reflection_object *intern;
6450
5
  const property_reference *ref;
6451
6452
5
  ZEND_PARSE_PARAMETERS_NONE();
6453
6454
5
  GET_REFLECTION_OBJECT_PTR(ref);
6455
6456
5
  const zend_property_info *prop_info = ref->prop;
6457
6458
5
  if (prop_info == NULL) {
6459
0
    RETURN_FALSE;
6460
0
  }
6461
6462
5
  const zval *prop = property_get_default(prop_info);
6463
5
  RETURN_BOOL(prop && !Z_ISUNDEF_P(prop));
6464
5
}
6465
/* }}} */
6466
6467
/* {{{ Returns the default value of a property */
6468
ZEND_METHOD(ReflectionProperty, getDefaultValue)
6469
6
{
6470
6
  const reflection_object *intern;
6471
6
  const property_reference *ref;
6472
6473
6
  ZEND_PARSE_PARAMETERS_NONE();
6474
6475
6
  GET_REFLECTION_OBJECT_PTR(ref);
6476
6477
6
  const zend_property_info *prop_info = ref->prop;
6478
6479
6
  if (prop_info == NULL) {
6480
    // Dynamic property
6481
0
    zend_error(
6482
0
      E_DEPRECATED,
6483
0
      "ReflectionProperty::getDefaultValue() for a property without a default value is deprecated, "
6484
0
        "use ReflectionProperty::hasDefaultValue() to check if the default value exists"
6485
0
    );
6486
0
    return;
6487
0
  }
6488
6489
6
  zval *prop = property_get_default(prop_info);
6490
6
  if (!prop || Z_ISUNDEF_P(prop)) {
6491
5
    zend_error(
6492
5
      E_DEPRECATED,
6493
5
      "ReflectionProperty::getDefaultValue() for a property without a default value is deprecated, "
6494
5
        "use ReflectionProperty::hasDefaultValue() to check if the default value exists"
6495
5
    );
6496
5
    return;
6497
5
  }
6498
6499
  /* copy: enforce read only access */
6500
1
  ZVAL_DEREF(prop);
6501
1
  ZVAL_COPY_OR_DUP(return_value, prop);
6502
6503
  /* this is necessary to make it able to work with default array
6504
  * properties, returned to user */
6505
1
  if (Z_TYPE_P(return_value) == IS_CONSTANT_AST
6506
0
    && UNEXPECTED(zval_update_constant_ex(return_value, prop_info->ce) != SUCCESS)
6507
1
  ) {
6508
0
    RETURN_THROWS();
6509
0
  }
6510
1
}
6511
/* }}} */
6512
6513
ZEND_METHOD(ReflectionProperty, hasHooks)
6514
47
{
6515
47
  const reflection_object *intern;
6516
47
  const property_reference *ref;
6517
6518
47
  ZEND_PARSE_PARAMETERS_NONE();
6519
6520
47
  GET_REFLECTION_OBJECT_PTR(ref);
6521
6522
47
  RETURN_BOOL(ref->prop && ref->prop->hooks);
6523
47
}
6524
6525
ZEND_METHOD(ReflectionProperty, getHooks)
6526
47
{
6527
47
  const reflection_object *intern;
6528
47
  const property_reference *ref;
6529
6530
47
  ZEND_PARSE_PARAMETERS_NONE();
6531
6532
47
  GET_REFLECTION_OBJECT_PTR(ref);
6533
6534
  // ref->prop can be missing for dynamic properties
6535
47
  if (!ref->prop || !ref->prop->hooks) {
6536
44
    RETURN_EMPTY_ARRAY();
6537
44
  }
6538
6539
3
  array_init(return_value);
6540
3
  if (ref->prop->hooks[ZEND_PROPERTY_HOOK_GET]) {
6541
2
    zval hook_obj;
6542
2
    zend_function *hook = ref->prop->hooks[ZEND_PROPERTY_HOOK_GET];
6543
2
    reflection_method_factory(hook->common.scope, hook, NULL, &hook_obj);
6544
2
    zend_hash_update(Z_ARRVAL_P(return_value), ZSTR_KNOWN(ZEND_STR_GET), &hook_obj);
6545
2
  }
6546
3
  if (ref->prop->hooks[ZEND_PROPERTY_HOOK_SET]) {
6547
2
    zval hook_obj;
6548
2
    zend_function *hook = ref->prop->hooks[ZEND_PROPERTY_HOOK_SET];
6549
2
    reflection_method_factory(hook->common.scope, hook, NULL, &hook_obj);
6550
2
    zend_hash_update(Z_ARRVAL_P(return_value), ZSTR_KNOWN(ZEND_STR_SET), &hook_obj);
6551
2
  }
6552
3
}
6553
6554
ZEND_METHOD(ReflectionProperty, hasHook)
6555
0
{
6556
0
  const reflection_object *intern;
6557
0
  const property_reference *ref;
6558
0
  zend_enum_PropertyHookType type;
6559
6560
0
  ZEND_PARSE_PARAMETERS_START(1, 1)
6561
0
    Z_PARAM_ENUM(type, reflection_property_hook_type_ptr)
6562
0
  ZEND_PARSE_PARAMETERS_END();
6563
6564
0
  GET_REFLECTION_OBJECT_PTR(ref);
6565
6566
0
  zend_property_hook_kind kind;
6567
0
  if (type == ZEND_ENUM_PropertyHookType_Get) {
6568
0
    kind = ZEND_PROPERTY_HOOK_GET;
6569
0
  } else {
6570
0
    kind = ZEND_PROPERTY_HOOK_SET;
6571
0
  }
6572
6573
0
  RETURN_BOOL(ref->prop && ref->prop->hooks && ref->prop->hooks[kind]);
6574
0
}
6575
6576
ZEND_METHOD(ReflectionProperty, getHook)
6577
55
{
6578
55
  const reflection_object *intern;
6579
55
  const property_reference *ref;
6580
55
  zend_enum_PropertyHookType type;
6581
6582
165
  ZEND_PARSE_PARAMETERS_START(1, 1)
6583
275
    Z_PARAM_ENUM(type, reflection_property_hook_type_ptr)
6584
55
  ZEND_PARSE_PARAMETERS_END();
6585
6586
55
  GET_REFLECTION_OBJECT_PTR(ref);
6587
6588
  // ref->prop can be missing for dynamic properties
6589
55
  if (!ref->prop || !ref->prop->hooks) {
6590
0
    RETURN_NULL();
6591
0
  }
6592
6593
55
  zend_function *hook;
6594
55
  if (type == ZEND_ENUM_PropertyHookType_Get) {
6595
30
    hook = ref->prop->hooks[ZEND_PROPERTY_HOOK_GET];
6596
30
  } else {
6597
25
    hook = ref->prop->hooks[ZEND_PROPERTY_HOOK_SET];
6598
25
  }
6599
6600
55
  if (!hook) {
6601
0
    RETURN_NULL();
6602
0
  }
6603
6604
55
  reflection_method_factory(hook->common.scope, hook, NULL, return_value);
6605
55
}
6606
6607
ZEND_METHOD(ReflectionProperty, isFinal)
6608
3
{
6609
3
  _property_check_flag(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_FINAL);
6610
3
}
6611
6612
static zend_result get_ce_from_scope_name(zend_class_entry **scope, zend_string *scope_name)
6613
4
{
6614
4
  if (!scope_name) {
6615
1
    *scope = NULL;
6616
1
    return SUCCESS;
6617
1
  }
6618
6619
3
  *scope = zend_lookup_class(scope_name);
6620
3
  if (!*scope) {
6621
2
    zend_throw_error(NULL, "Class \"%pS\" not found", scope_name);
6622
2
    return FAILURE;
6623
2
  }
6624
1
  return SUCCESS;
6625
3
}
6626
6627
static zend_always_inline uint32_t set_visibility_to_visibility(uint32_t set_visibility)
6628
0
{
6629
0
  switch (set_visibility) {
6630
0
    case ZEND_ACC_PUBLIC_SET:
6631
0
      return ZEND_ACC_PUBLIC;
6632
0
    case ZEND_ACC_PROTECTED_SET:
6633
0
      return ZEND_ACC_PROTECTED;
6634
0
    case ZEND_ACC_PRIVATE_SET:
6635
0
      return ZEND_ACC_PRIVATE;
6636
0
    default: ZEND_UNREACHABLE();
6637
0
  }
6638
0
}
6639
6640
static bool check_visibility(uint32_t visibility, const zend_class_entry *ce, const zend_class_entry *scope)
6641
2
{
6642
2
  if (!(visibility & ZEND_ACC_PUBLIC) && (scope != ce)) {
6643
1
    if (!scope) {
6644
1
      return false;
6645
1
    }
6646
0
    if (visibility & ZEND_ACC_PRIVATE) {
6647
0
      return false;
6648
0
    }
6649
0
    ZEND_ASSERT(visibility & ZEND_ACC_PROTECTED);
6650
0
    if (!instanceof_function(scope, ce) && !instanceof_function(ce, scope)) {
6651
0
      return false;
6652
0
    }
6653
0
  }
6654
1
  return true;
6655
2
}
6656
6657
ZEND_METHOD(ReflectionProperty, isReadable)
6658
24
{
6659
24
  const reflection_object *intern;
6660
24
  const property_reference *ref;
6661
24
  zend_string *scope_name;
6662
24
  zend_object *obj = NULL;
6663
6664
72
  ZEND_PARSE_PARAMETERS_START(1, 2)
6665
96
    Z_PARAM_STR_OR_NULL(scope_name)
6666
24
    Z_PARAM_OPTIONAL
6667
94
    Z_PARAM_OBJ_OR_NULL(obj)
6668
24
  ZEND_PARSE_PARAMETERS_END();
6669
6670
24
  GET_REFLECTION_OBJECT_PTR(ref);
6671
6672
24
  zend_property_info *prop = ref->prop;
6673
24
  if (prop && obj) {
6674
0
    if (prop->flags & ZEND_ACC_STATIC) {
6675
0
      zend_throw_exception(reflection_exception_ptr, "null is expected as object argument for static properties", 0);
6676
0
      RETURN_THROWS();
6677
0
    }
6678
0
    if (!instanceof_function(obj->ce, prop->ce)) {
6679
0
      zend_throw_exception(reflection_exception_ptr, "Given object is not an instance of the class this property was declared in", 0);
6680
0
      RETURN_THROWS();
6681
0
    }
6682
0
    prop = reflection_property_get_effective_prop(ref->prop,
6683
0
        ref->unmangled_name, intern->ce, obj);
6684
0
  }
6685
6686
24
  zend_class_entry *ce = obj ? obj->ce : intern->ce;
6687
24
  if (!prop) {
6688
22
    if (obj && obj->properties && zend_hash_find(obj->properties, ref->unmangled_name)) {
6689
10
      RETURN_TRUE;
6690
10
    }
6691
12
handle_magic_get:
6692
12
    if (ce->__get) {
6693
0
      if (obj && ce->__isset) {
6694
0
        uint32_t *guard = zend_get_property_guard(obj, ref->unmangled_name);
6695
0
        if (!((*guard) & ZEND_GUARD_PROPERTY_ISSET)) {
6696
0
          GC_ADDREF(obj);
6697
0
          *guard |= ZEND_GUARD_PROPERTY_ISSET;
6698
0
          zval member;
6699
0
          ZVAL_STR(&member, ref->unmangled_name);
6700
0
          zend_call_known_instance_method_with_1_params(ce->__isset, obj, return_value, &member);
6701
6702
0
          if (Z_TYPE_P(return_value) == IS_REFERENCE) {
6703
0
            zend_unwrap_reference(return_value);
6704
0
          }
6705
6706
0
          *guard &= ~ZEND_GUARD_PROPERTY_ISSET;
6707
0
          OBJ_RELEASE(obj);
6708
0
          return;
6709
0
        }
6710
0
      }
6711
0
      RETURN_TRUE;
6712
0
    }
6713
12
    if (obj && zend_lazy_object_must_init(obj)) {
6714
3
      obj = zend_lazy_object_init(obj);
6715
3
      if (!obj) {
6716
0
        RETURN_THROWS();
6717
0
      }
6718
3
      if (obj->properties && zend_hash_find(obj->properties, ref->unmangled_name)) {
6719
3
        RETURN_TRUE;
6720
3
      }
6721
3
    }
6722
9
    RETURN_FALSE;
6723
9
  }
6724
6725
2
  zend_class_entry *scope;
6726
2
  if (get_ce_from_scope_name(&scope, scope_name) == FAILURE) {
6727
1
    RETURN_THROWS();
6728
1
  }
6729
6730
1
  if (!check_visibility(prop->flags & ZEND_ACC_PPP_MASK, prop->ce, scope)) {
6731
0
    if (!(prop->flags & ZEND_ACC_STATIC)) {
6732
0
      goto handle_magic_get;
6733
0
    }
6734
0
    RETURN_FALSE;
6735
0
  }
6736
6737
1
  if (prop->flags & ZEND_ACC_VIRTUAL) {
6738
0
    ZEND_ASSERT(prop->hooks);
6739
0
    if (!prop->hooks[ZEND_PROPERTY_HOOK_GET]) {
6740
0
      RETURN_FALSE;
6741
0
    }
6742
1
  } else if (obj && (!prop->hooks || !prop->hooks[ZEND_PROPERTY_HOOK_GET])) {
6743
0
retry_declared:;
6744
0
    zval *prop_val = OBJ_PROP(obj, prop->offset);
6745
0
    if (Z_TYPE_P(prop_val) == IS_UNDEF) {
6746
0
      if (zend_lazy_object_must_init(obj) && (Z_PROP_FLAG_P(prop_val) & IS_PROP_LAZY)) {
6747
0
        obj = zend_lazy_object_init(obj);
6748
0
        if (!obj) {
6749
0
          RETURN_THROWS();
6750
0
        }
6751
0
        goto retry_declared;
6752
0
      }
6753
0
      if (!(Z_PROP_FLAG_P(prop_val) & IS_PROP_UNINIT)) {
6754
0
        goto handle_magic_get;
6755
0
      }
6756
0
      RETURN_FALSE;
6757
0
    }
6758
1
  } else if (prop->flags & ZEND_ACC_STATIC) {
6759
0
    if (ce->default_static_members_count && !CE_STATIC_MEMBERS(ce)) {
6760
0
      zend_class_init_statics(ce);
6761
0
    }
6762
0
    zval *prop_val = CE_STATIC_MEMBERS(ce) + prop->offset;
6763
0
    RETURN_BOOL(!Z_ISUNDEF_P(prop_val));
6764
0
  }
6765
6766
1
  RETURN_TRUE;
6767
1
}
6768
6769
ZEND_METHOD(ReflectionProperty, isWritable)
6770
2
{
6771
2
  const reflection_object *intern;
6772
2
  const property_reference *ref;
6773
2
  zend_string *scope_name;
6774
2
  zend_object *obj = NULL;
6775
6776
6
  ZEND_PARSE_PARAMETERS_START(1, 2)
6777
8
    Z_PARAM_STR_OR_NULL(scope_name)
6778
2
    Z_PARAM_OPTIONAL
6779
8
    Z_PARAM_OBJ_OR_NULL(obj)
6780
2
  ZEND_PARSE_PARAMETERS_END();
6781
6782
2
  GET_REFLECTION_OBJECT_PTR(ref);
6783
6784
2
  zend_property_info *prop = ref->prop;
6785
2
  if (prop && obj) {
6786
1
    if (prop->flags & ZEND_ACC_STATIC) {
6787
0
      zend_throw_exception(reflection_exception_ptr, "null is expected as object argument for static properties", 0);
6788
0
      RETURN_THROWS();
6789
0
    }
6790
1
    if (!instanceof_function(obj->ce, prop->ce)) {
6791
0
      zend_throw_exception(reflection_exception_ptr, "Given object is not an instance of the class this property was declared in", 0);
6792
0
      RETURN_THROWS();
6793
0
    }
6794
1
    prop = reflection_property_get_effective_prop(ref->prop,
6795
1
        ref->unmangled_name, intern->ce, obj);
6796
1
  }
6797
6798
2
  const zend_class_entry *ce = obj ? obj->ce : intern->ce;
6799
2
  if (!prop) {
6800
0
    if (!(ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) {
6801
0
      RETURN_TRUE;
6802
0
    }
6803
    /* This path is effectively unreachable, but theoretically possible for
6804
     * two internal classes where ZEND_ACC_NO_DYNAMIC_PROPERTIES is only
6805
     * added to the subclass, in which case a ReflectionProperty can be
6806
     * constructed on the parent class, and then tested on the subclass. */
6807
1
handle_magic_set:
6808
1
    RETURN_BOOL(ce->__set);
6809
1
  }
6810
6811
2
  zend_class_entry *scope;
6812
2
  if (get_ce_from_scope_name(&scope, scope_name) == FAILURE) {
6813
1
    RETURN_THROWS();
6814
1
  }
6815
6816
1
  if (!check_visibility(prop->flags & ZEND_ACC_PPP_MASK, prop->ce, scope)) {
6817
1
    if (!(prop->flags & ZEND_ACC_STATIC)) {
6818
1
      goto handle_magic_set;
6819
1
    }
6820
0
    RETURN_FALSE;
6821
0
  }
6822
0
  uint32_t set_visibility = prop->flags & ZEND_ACC_PPP_SET_MASK;
6823
0
  if (!set_visibility) {
6824
0
    set_visibility = zend_visibility_to_set_visibility(prop->flags & ZEND_ACC_PPP_MASK);
6825
0
  }
6826
0
  if (!check_visibility(set_visibility_to_visibility(set_visibility), prop->ce, scope)) {
6827
0
    RETURN_FALSE;
6828
0
  }
6829
6830
0
  if (prop->flags & ZEND_ACC_VIRTUAL) {
6831
0
    ZEND_ASSERT(prop->hooks);
6832
0
    if (!prop->hooks[ZEND_PROPERTY_HOOK_SET]) {
6833
0
      RETURN_FALSE;
6834
0
    }
6835
0
  } else if (obj && (prop->flags & ZEND_ACC_READONLY)) {
6836
0
retry:;
6837
0
    zval *prop_val = OBJ_PROP(obj, prop->offset);
6838
0
    if (Z_TYPE_P(prop_val) == IS_UNDEF
6839
0
      && zend_lazy_object_must_init(obj)
6840
0
      && (Z_PROP_FLAG_P(prop_val) & IS_PROP_LAZY)
6841
0
    ) {
6842
0
      obj = zend_lazy_object_init(obj);
6843
0
      if (!obj) {
6844
0
        RETURN_THROWS();
6845
0
      }
6846
0
      goto retry;
6847
0
    }
6848
0
    if (Z_TYPE_P(prop_val) != IS_UNDEF && !(Z_PROP_FLAG_P(prop_val) & IS_PROP_REINITABLE)) {
6849
0
      RETURN_FALSE;
6850
0
    }
6851
0
  }
6852
6853
0
  RETURN_TRUE;
6854
0
}
6855
6856
/* {{{ Constructor. Throws an Exception in case the given extension does not exist */
6857
ZEND_METHOD(ReflectionExtension, __construct)
6858
44
{
6859
44
  zend_string *name_str;
6860
6861
44
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name_str) == FAILURE) {
6862
4
    RETURN_THROWS();
6863
4
  }
6864
6865
40
  zval *object = ZEND_THIS;
6866
40
  reflection_object *intern = Z_REFLECTION_P(object);
6867
40
  zend_module_entry *module;
6868
40
  if ((module = zend_hash_find_ptr_lc(&module_registry, name_str)) == NULL) {
6869
1
    zend_throw_exception_ex(reflection_exception_ptr, 0,
6870
1
      "Extension \"%pS\" does not exist", name_str);
6871
1
    RETURN_THROWS();
6872
1
  }
6873
39
  zval *prop_name = reflection_prop_name(object);
6874
39
  zval_ptr_dtor(prop_name);
6875
39
  ZVAL_STRING(prop_name, module->name);
6876
39
  intern->ptr = module;
6877
39
  intern->ref_type = REF_TYPE_OTHER;
6878
39
  intern->ce = NULL;
6879
39
}
6880
/* }}} */
6881
6882
/* {{{ Returns a string representation */
6883
ZEND_METHOD(ReflectionExtension, __toString)
6884
3
{
6885
3
  const reflection_object *intern;
6886
3
  const zend_module_entry *module;
6887
3
  smart_str str = {0};
6888
6889
3
  ZEND_PARSE_PARAMETERS_NONE();
6890
3
  GET_REFLECTION_OBJECT_PTR(module);
6891
3
  _extension_string(&str, module);
6892
3
  RETURN_STR(smart_str_extract(&str));
6893
3
}
6894
/* }}} */
6895
6896
/* {{{ Returns this extension's name */
6897
ZEND_METHOD(ReflectionExtension, getName)
6898
1
{
6899
1
  const reflection_object *intern;
6900
1
  const zend_module_entry *module;
6901
6902
1
  ZEND_PARSE_PARAMETERS_NONE();
6903
6904
1
  GET_REFLECTION_OBJECT_PTR(module);
6905
1
  RETURN_STRING(module->name);
6906
1
}
6907
/* }}} */
6908
6909
/* {{{ Returns this extension's version */
6910
ZEND_METHOD(ReflectionExtension, getVersion)
6911
3
{
6912
3
  const reflection_object *intern;
6913
3
  const zend_module_entry *module;
6914
6915
3
  ZEND_PARSE_PARAMETERS_NONE();
6916
3
  GET_REFLECTION_OBJECT_PTR(module);
6917
6918
  /* An extension does not necessarily have a version number */
6919
3
  if (module->version == NO_VERSION_YET) {
6920
0
    RETURN_NULL();
6921
3
  } else {
6922
3
    RETURN_STRING(module->version);
6923
3
  }
6924
3
}
6925
/* }}} */
6926
6927
/* {{{ Returns an array of this extension's functions */
6928
ZEND_METHOD(ReflectionExtension, getFunctions)
6929
2
{
6930
2
  const reflection_object *intern;
6931
2
  const zend_module_entry *module;
6932
2
  zval function;
6933
6934
2
  ZEND_PARSE_PARAMETERS_NONE();
6935
2
  GET_REFLECTION_OBJECT_PTR(module);
6936
6937
2
  array_init(return_value);
6938
2.77k
  ZEND_HASH_MAP_FOREACH_PTR(CG(function_table), zend_function *fptr) {
6939
2.77k
    if (fptr->common.type==ZEND_INTERNAL_FUNCTION
6940
1.38k
      && fptr->internal_function.module == module
6941
2.77k
    ) {
6942
1.03k
      reflection_function_factory(fptr, NULL, &function);
6943
1.03k
      zend_hash_update(Z_ARRVAL_P(return_value), fptr->common.function_name, &function);
6944
1.03k
    }
6945
2.77k
  } ZEND_HASH_FOREACH_END();
6946
2
}
6947
/* }}} */
6948
6949
/* {{{ Returns an associative array containing this extension's constants and their values */
6950
ZEND_METHOD(ReflectionExtension, getConstants)
6951
1
{
6952
1
  const reflection_object *intern;
6953
1
  const zend_module_entry *module;
6954
6955
1
  ZEND_PARSE_PARAMETERS_NONE();
6956
1
  GET_REFLECTION_OBJECT_PTR(module);
6957
6958
1
  array_init(return_value);
6959
1.10k
  ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), zend_constant *constant) {
6960
1.10k
    if (module->module_number == ZEND_CONSTANT_MODULE_NUMBER(constant)) {
6961
396
      zval const_val;
6962
396
      ZVAL_COPY_OR_DUP(&const_val, &constant->value);
6963
396
      zend_hash_update(Z_ARRVAL_P(return_value), constant->name, &const_val);
6964
396
    }
6965
1.10k
  } ZEND_HASH_FOREACH_END();
6966
1
}
6967
/* }}} */
6968
6969
/* {{{ _addinientry */
6970
static void _addinientry(const zend_ini_entry *ini_entry, const zval *retval, int number)
6971
179
{
6972
179
  if (number == ini_entry->module_number) {
6973
14
    zval zv;
6974
14
    if (ini_entry->value) {
6975
11
      ZVAL_STR_COPY(&zv, ini_entry->value);
6976
11
    } else {
6977
3
      ZVAL_NULL(&zv);
6978
3
    }
6979
14
    zend_symtable_update(Z_ARRVAL_P(retval), ini_entry->name, &zv);
6980
14
  }
6981
179
}
6982
/* }}} */
6983
6984
/* {{{ Returns an associative array containing this extension's INI entries and their values */
6985
ZEND_METHOD(ReflectionExtension, getINIEntries)
6986
1
{
6987
1
  const reflection_object *intern;
6988
1
  const zend_module_entry *module;
6989
6990
1
  ZEND_PARSE_PARAMETERS_NONE();
6991
1
  GET_REFLECTION_OBJECT_PTR(module);
6992
6993
1
  array_init(return_value);
6994
360
  ZEND_HASH_MAP_FOREACH_PTR(EG(ini_directives), zend_ini_entry *ini_entry) {
6995
360
    _addinientry(ini_entry, return_value, module->module_number);
6996
360
  } ZEND_HASH_FOREACH_END();
6997
1
}
6998
/* }}} */
6999
7000
/* {{{ add_extension_class */
7001
static void add_extension_class(zend_class_entry *ce, zend_string *key, zval *class_array, const zend_module_entry *module, bool add_reflection_class)
7002
588
{
7003
588
  if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module && !strcasecmp(ce->info.internal.module->name, module->name)) {
7004
81
    zend_string *name;
7005
7006
81
    if (!zend_string_equals_ci(ce->name, key)) {
7007
      /* This is a class alias, use alias name */
7008
0
      name = key;
7009
81
    } else {
7010
      /* Use class name */
7011
81
      name = ce->name;
7012
81
    }
7013
81
    if (add_reflection_class) {
7014
52
      zval zclass;
7015
52
      zend_reflection_class_factory(ce, &zclass);
7016
52
      zend_hash_update(Z_ARRVAL_P(class_array), name, &zclass);
7017
52
    } else {
7018
29
      add_next_index_str(class_array, zend_string_copy(name));
7019
29
    }
7020
81
  }
7021
588
}
7022
/* }}} */
7023
7024
/* {{{ Returns an array containing ReflectionClass objects for all classes of this extension */
7025
ZEND_METHOD(ReflectionExtension, getClasses)
7026
2
{
7027
2
  const reflection_object *intern;
7028
2
  const zend_module_entry *module;
7029
7030
2
  ZEND_PARSE_PARAMETERS_NONE();
7031
2
  GET_REFLECTION_OBJECT_PTR(module);
7032
7033
2
  array_init(return_value);
7034
788
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(class_table), zend_string *key, zend_class_entry *ce) {
7035
788
    add_extension_class(ce, key, return_value, module, true);
7036
788
  } ZEND_HASH_FOREACH_END();
7037
2
}
7038
/* }}} */
7039
7040
/* {{{ Returns an array containing all names of all classes of this extension */
7041
ZEND_METHOD(ReflectionExtension, getClassNames)
7042
1
{
7043
1
  const reflection_object *intern;
7044
1
  const zend_module_entry *module;
7045
7046
1
  ZEND_PARSE_PARAMETERS_NONE();
7047
1
  GET_REFLECTION_OBJECT_PTR(module);
7048
7049
1
  array_init(return_value);
7050
394
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(class_table), zend_string *key, zend_class_entry *ce) {
7051
394
    add_extension_class(ce, key, return_value, module, false);
7052
394
  } ZEND_HASH_FOREACH_END();
7053
1
}
7054
/* }}} */
7055
7056
/* {{{ Returns an array containing all names of all extensions this extension depends on */
7057
ZEND_METHOD(ReflectionExtension, getDependencies)
7058
1
{
7059
1
  const reflection_object *intern;
7060
1
  const zend_module_entry *module;
7061
7062
1
  ZEND_PARSE_PARAMETERS_NONE();
7063
1
  GET_REFLECTION_OBJECT_PTR(module);
7064
7065
1
  const zend_module_dep *dep = module->deps;
7066
7067
1
  if (!dep) {
7068
0
    RETURN_EMPTY_ARRAY();
7069
0
  }
7070
7071
1
  array_init(return_value);
7072
4
  while (dep->name) {
7073
3
    const char *rel_type;
7074
3
    size_t len = 0;
7075
7076
3
    switch(dep->type) {
7077
2
      case MODULE_DEP_REQUIRED:
7078
2
        rel_type = "Required";
7079
2
        len += sizeof("Required") - 1;
7080
2
        break;
7081
0
      case MODULE_DEP_CONFLICTS:
7082
0
        rel_type = "Conflicts";
7083
0
        len += sizeof("Conflicts") - 1;
7084
0
        break;
7085
1
      case MODULE_DEP_OPTIONAL:
7086
1
        rel_type = "Optional";
7087
1
        len += sizeof("Optional") - 1;
7088
1
        break;
7089
0
      default:
7090
0
        rel_type = "Error"; /* shouldn't happen */
7091
0
        len += sizeof("Error") - 1;
7092
0
        break;
7093
3
    }
7094
7095
3
    if (dep->rel) {
7096
0
      len += strlen(dep->rel) + 1;
7097
0
    }
7098
7099
3
    if (dep->version) {
7100
0
      len += strlen(dep->version) + 1;
7101
0
    }
7102
7103
3
    zend_string *relation = zend_string_alloc(len, false);
7104
3
    snprintf(ZSTR_VAL(relation), ZSTR_LEN(relation) + 1, "%s%s%s%s%s",
7105
3
            rel_type,
7106
3
            dep->rel ? " " : "",
7107
3
            dep->rel ? dep->rel : "",
7108
3
            dep->version ? " " : "",
7109
3
            dep->version ? dep->version : "");
7110
3
    add_assoc_str(return_value, dep->name, relation);
7111
3
    dep++;
7112
3
  }
7113
1
}
7114
/* }}} */
7115
7116
/* {{{ Prints phpinfo block for the extension */
7117
ZEND_METHOD(ReflectionExtension, info)
7118
11
{
7119
11
  const reflection_object *intern;
7120
11
  zend_module_entry *module;
7121
7122
11
  ZEND_PARSE_PARAMETERS_NONE();
7123
11
  GET_REFLECTION_OBJECT_PTR(module);
7124
7125
11
  php_info_print_module(module);
7126
11
}
7127
/* }}} */
7128
7129
/* {{{ Returns whether this extension is persistent */
7130
ZEND_METHOD(ReflectionExtension, isPersistent)
7131
17
{
7132
17
  const reflection_object *intern;
7133
17
  const zend_module_entry *module;
7134
7135
17
  ZEND_PARSE_PARAMETERS_NONE();
7136
17
  GET_REFLECTION_OBJECT_PTR(module);
7137
7138
17
  RETURN_BOOL(module->type == MODULE_PERSISTENT);
7139
17
}
7140
/* }}} */
7141
7142
/* {{{ Returns whether this extension is temporary */
7143
ZEND_METHOD(ReflectionExtension, isTemporary)
7144
1
{
7145
1
  const reflection_object *intern;
7146
1
  const zend_module_entry *module;
7147
7148
1
  ZEND_PARSE_PARAMETERS_NONE();
7149
1
  GET_REFLECTION_OBJECT_PTR(module);
7150
7151
1
  RETURN_BOOL(module->type == MODULE_TEMPORARY);
7152
1
}
7153
/* }}} */
7154
7155
/* {{{ Constructor. Throws an Exception in case the given Zend extension does not exist */
7156
ZEND_METHOD(ReflectionZendExtension, __construct)
7157
7
{
7158
7
  zend_string *name_zstr;
7159
7160
7
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name_zstr) == FAILURE) {
7161
4
    RETURN_THROWS();
7162
4
  }
7163
7164
3
  zval *object = ZEND_THIS;
7165
3
  reflection_object *intern = Z_REFLECTION_P(object);
7166
7167
3
  zend_extension *extension = zend_get_extension(ZSTR_VAL(name_zstr));
7168
3
  if (!extension) {
7169
2
    zend_throw_exception_ex(reflection_exception_ptr, 0,
7170
2
        "Zend Extension \"%pS\" does not exist", name_zstr);
7171
2
    RETURN_THROWS();
7172
2
  }
7173
1
  ZVAL_STRING(reflection_prop_name(object), extension->name);
7174
1
  intern->ptr = extension;
7175
1
  intern->ref_type = REF_TYPE_OTHER;
7176
1
  intern->ce = NULL;
7177
1
}
7178
/* }}} */
7179
7180
/* {{{ Returns a string representation */
7181
ZEND_METHOD(ReflectionZendExtension, __toString)
7182
0
{
7183
0
  const reflection_object *intern;
7184
0
  const zend_extension *extension;
7185
0
  smart_str str = {0};
7186
7187
0
  ZEND_PARSE_PARAMETERS_NONE();
7188
0
  GET_REFLECTION_OBJECT_PTR(extension);
7189
0
  _zend_extension_string(&str, extension);
7190
0
  RETURN_STR(smart_str_extract(&str));
7191
0
}
7192
/* }}} */
7193
7194
/* {{{ Returns the name of this Zend extension */
7195
ZEND_METHOD(ReflectionZendExtension, getName)
7196
1
{
7197
1
  const reflection_object *intern;
7198
1
  const zend_extension *extension;
7199
7200
1
  ZEND_PARSE_PARAMETERS_NONE();
7201
1
  GET_REFLECTION_OBJECT_PTR(extension);
7202
7203
1
  RETURN_STRING(extension->name);
7204
1
}
7205
/* }}} */
7206
7207
/* {{{ Returns the version information of this Zend extension */
7208
ZEND_METHOD(ReflectionZendExtension, getVersion)
7209
1
{
7210
1
  const reflection_object *intern;
7211
1
  const zend_extension *extension;
7212
7213
1
  ZEND_PARSE_PARAMETERS_NONE();
7214
1
  GET_REFLECTION_OBJECT_PTR(extension);
7215
7216
1
  if (extension->version) {
7217
1
    RETURN_STRING(extension->version);
7218
1
  } else {
7219
0
    RETURN_EMPTY_STRING();
7220
0
  }
7221
1
}
7222
/* }}} */
7223
7224
/* {{{ Returns the name of this Zend extension's author */
7225
ZEND_METHOD(ReflectionZendExtension, getAuthor)
7226
1
{
7227
1
  const reflection_object *intern;
7228
1
  const zend_extension *extension;
7229
7230
1
  ZEND_PARSE_PARAMETERS_NONE();
7231
1
  GET_REFLECTION_OBJECT_PTR(extension);
7232
7233
1
  if (extension->author) {
7234
1
    RETURN_STRING(extension->author);
7235
1
  } else {
7236
0
    RETURN_EMPTY_STRING();
7237
0
  }
7238
1
}
7239
/* }}} */
7240
7241
/* {{{ Returns this Zend extension's URL*/
7242
ZEND_METHOD(ReflectionZendExtension, getURL)
7243
1
{
7244
1
  const reflection_object *intern;
7245
1
  const zend_extension *extension;
7246
7247
1
  ZEND_PARSE_PARAMETERS_NONE();
7248
1
  GET_REFLECTION_OBJECT_PTR(extension);
7249
7250
1
  if (extension->URL) {
7251
1
    RETURN_STRING(extension->URL);
7252
1
  } else {
7253
0
    RETURN_EMPTY_STRING();
7254
0
  }
7255
1
}
7256
/* }}} */
7257
7258
/* {{{ Returns this Zend extension's copyright information */
7259
ZEND_METHOD(ReflectionZendExtension, getCopyright)
7260
1
{
7261
1
  const reflection_object *intern;
7262
1
  const zend_extension *extension;
7263
7264
1
  ZEND_PARSE_PARAMETERS_NONE();
7265
1
  GET_REFLECTION_OBJECT_PTR(extension);
7266
7267
1
  if (extension->copyright) {
7268
1
    RETURN_STRING(extension->copyright);
7269
1
  } else {
7270
0
    RETURN_EMPTY_STRING();
7271
0
  }
7272
1
}
7273
/* }}} */
7274
7275
/* {{{     Dummy constructor -- always throws ReflectionExceptions. */
7276
ZEND_METHOD(ReflectionReference, __construct)
7277
0
{
7278
0
  zend_throw_exception(reflection_exception_ptr,
7279
0
    "Cannot directly instantiate ReflectionReference. "
7280
0
    "Use ReflectionReference::fromArrayElement() instead", 0);
7281
0
}
7282
/* }}} */
7283
7284
1
static bool is_ignorable_reference(const HashTable *ht, const zval *ref) {
7285
1
  if (Z_REFCOUNT_P(ref) != 1) {
7286
0
    return false;
7287
0
  }
7288
7289
  /* Directly self-referential arrays are treated as proper references
7290
   * in zend_array_dup() despite rc=1. */
7291
1
  return Z_TYPE_P(Z_REFVAL_P(ref)) != IS_ARRAY || Z_ARRVAL_P(Z_REFVAL_P(ref)) != ht;
7292
1
}
7293
7294
/* {{{     Create ReflectionReference for array item. Returns null if not a reference. */
7295
ZEND_METHOD(ReflectionReference, fromArrayElement)
7296
14
{
7297
14
  HashTable *ht;
7298
14
  zend_string *string_key = NULL;
7299
14
  zend_long int_key = 0;
7300
7301
42
  ZEND_PARSE_PARAMETERS_START(2, 2)
7302
56
    Z_PARAM_ARRAY_HT(ht)
7303
54
    Z_PARAM_STR_OR_LONG(string_key, int_key)
7304
54
  ZEND_PARSE_PARAMETERS_END();
7305
7306
9
  zval *item;
7307
9
  if (string_key) {
7308
8
    item = zend_hash_find(ht, string_key);
7309
8
  } else {
7310
1
    item = zend_hash_index_find(ht, int_key);
7311
1
  }
7312
7313
9
  if (!item) {
7314
3
    zend_throw_exception(reflection_exception_ptr, "Array key not found", 0);
7315
3
    RETURN_THROWS();
7316
3
  }
7317
7318
6
  if (Z_TYPE_P(item) != IS_REFERENCE || is_ignorable_reference(ht, item)) {
7319
5
    RETURN_NULL();
7320
5
  }
7321
7322
1
  object_init_ex(return_value, reflection_reference_ptr);
7323
1
  reflection_object *intern = Z_REFLECTION_P(return_value);
7324
1
  ZVAL_COPY(&intern->obj, item);
7325
1
  intern->ref_type = REF_TYPE_OTHER;
7326
1
}
7327
/* }}} */
7328
7329
/* {{{     Returns a unique identifier for the reference.
7330
 *     The format of the return value is unspecified and may change. */
7331
ZEND_METHOD(ReflectionReference, getId)
7332
0
{
7333
0
  ZEND_PARSE_PARAMETERS_NONE();
7334
7335
0
  reflection_object *intern = Z_REFLECTION_P(ZEND_THIS);
7336
0
  if (Z_TYPE(intern->obj) != IS_REFERENCE) {
7337
0
    zend_throw_exception(reflection_exception_ptr, "Corrupted ReflectionReference object", 0);
7338
0
    RETURN_THROWS();
7339
0
  }
7340
7341
0
  if (!REFLECTION_G(key_initialized)) {
7342
0
    if (php_random_bytes_throw(&REFLECTION_G(key), 16) == FAILURE) {
7343
0
      RETURN_THROWS();
7344
0
    }
7345
7346
0
    REFLECTION_G(key_initialized) = true;
7347
0
  }
7348
7349
  /* SHA1(ref || key) to avoid directly exposing memory addresses. */
7350
0
  PHP_SHA1_CTX context;
7351
0
  PHP_SHA1Init(&context);
7352
0
  PHP_SHA1Update(&context, (unsigned char *) &Z_REF(intern->obj), sizeof(zend_reference *));
7353
0
  PHP_SHA1Update(&context, REFLECTION_G(key), REFLECTION_KEY_LEN);
7354
0
  unsigned char digest[20];
7355
0
  PHP_SHA1Final(digest, &context);
7356
7357
0
  RETURN_STRINGL((char *) digest, sizeof(digest));
7358
0
}
7359
/* }}} */
7360
7361
ZEND_METHOD(ReflectionAttribute, __construct)
7362
0
{
7363
0
  zend_throw_exception(reflection_exception_ptr, "Cannot directly instantiate ReflectionAttribute", 0);
7364
0
}
7365
7366
ZEND_METHOD(ReflectionAttribute, __clone)
7367
0
{
7368
  /* __clone() is private but this is reachable with reflection */
7369
0
  zend_throw_exception(reflection_exception_ptr, "Cannot clone object using __clone()", 0);
7370
0
}
7371
7372
/* {{{ Returns a string representation */
7373
ZEND_METHOD(ReflectionAttribute, __toString)
7374
59
{
7375
59
  const reflection_object *intern;
7376
59
  const attribute_reference *attr;
7377
7378
59
  ZEND_PARSE_PARAMETERS_NONE();
7379
7380
59
  GET_REFLECTION_OBJECT_PTR(attr);
7381
7382
59
  smart_str str = {0};
7383
59
  smart_str_appends(&str, "Attribute [ ");
7384
59
  smart_str_append(&str, attr->data->name);
7385
59
  smart_str_appends(&str, " ]");
7386
7387
59
  if (attr->data->argc > 0) {
7388
52
    smart_str_appends(&str, " {\n");
7389
52
    smart_str_append_printf(&str, "  - Arguments [%" PRIu32 "] {\n", attr->data->argc);
7390
7391
218
    for (uint32_t i = 0; i < attr->data->argc; i++) {
7392
166
      smart_str_append_printf(&str, "    Argument #%" PRIu32 " [ ", i);
7393
166
      if (attr->data->args[i].name != NULL) {
7394
14
        smart_str_append(&str, attr->data->args[i].name);
7395
14
        smart_str_appends(&str, " = ");
7396
14
      }
7397
7398
166
      format_default_value(&str, &attr->data->args[i].value);
7399
7400
166
      smart_str_appends(&str, " ]\n");
7401
166
    }
7402
52
    smart_str_appends(&str, "  }\n");
7403
7404
52
    smart_str_appends(&str, "}\n");
7405
52
  } else {
7406
7
    smart_str_appendc(&str, '\n');
7407
7
  }
7408
7409
59
  RETURN_STR(smart_str_extract(&str));
7410
59
}
7411
/* }}} */
7412
7413
/* {{{ Returns the name of the attribute */
7414
ZEND_METHOD(ReflectionAttribute, getName)
7415
531
{
7416
531
  const reflection_object *intern;
7417
531
  const attribute_reference *attr;
7418
7419
531
  ZEND_PARSE_PARAMETERS_NONE();
7420
531
  GET_REFLECTION_OBJECT_PTR(attr);
7421
7422
531
  RETURN_STR_COPY(attr->data->name);
7423
531
}
7424
/* }}} */
7425
7426
/* Returns whether this attribute name comes from a namespace */
7427
ZEND_METHOD(ReflectionAttribute, inNamespace)
7428
0
{
7429
0
  reflection_object *intern;
7430
0
  attribute_reference *attr;
7431
7432
0
  ZEND_PARSE_PARAMETERS_NONE();
7433
7434
0
  GET_REFLECTION_OBJECT_PTR(attr);
7435
7436
0
  const zend_string *name = attr->data->name;
7437
0
  const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
7438
0
  RETURN_BOOL(backslash);
7439
0
}
7440
/* }}} */
7441
7442
/* Returns the name of namespace where this attribute comes from */
7443
ZEND_METHOD(ReflectionAttribute, getNamespaceName)
7444
0
{
7445
0
  reflection_object *intern;
7446
0
  attribute_reference *attr;
7447
7448
0
  ZEND_PARSE_PARAMETERS_NONE();
7449
7450
0
  GET_REFLECTION_OBJECT_PTR(attr);
7451
7452
0
  const zend_string *name = attr->data->name;
7453
0
  const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
7454
0
  if (backslash) {
7455
0
    RETURN_STRINGL(ZSTR_VAL(name), backslash - ZSTR_VAL(name));
7456
0
  }
7457
0
  RETURN_EMPTY_STRING();
7458
0
}
7459
7460
/* Returns the short name of the attribute (without namespace part) */
7461
ZEND_METHOD(ReflectionAttribute, getShortName)
7462
0
{
7463
0
  reflection_object *intern;
7464
0
  attribute_reference *attr;
7465
7466
0
  ZEND_PARSE_PARAMETERS_NONE();
7467
7468
0
  GET_REFLECTION_OBJECT_PTR(attr);
7469
7470
0
  zend_string *name = attr->data->name;
7471
0
  const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name));
7472
0
  if (backslash) {
7473
0
    RETURN_STRINGL(backslash + 1, ZSTR_LEN(name) - (backslash - ZSTR_VAL(name) + 1));
7474
0
  }
7475
0
  RETURN_STR_COPY(name);
7476
0
}
7477
7478
/* {{{ Returns the target of the attribute */
7479
ZEND_METHOD(ReflectionAttribute, getTarget)
7480
53
{
7481
53
  const reflection_object *intern;
7482
53
  const attribute_reference *attr;
7483
7484
53
  ZEND_PARSE_PARAMETERS_NONE();
7485
53
  GET_REFLECTION_OBJECT_PTR(attr);
7486
7487
53
  RETURN_LONG(attr->target);
7488
53
}
7489
/* }}} */
7490
7491
/* {{{ Returns true if the attribute is repeated */
7492
ZEND_METHOD(ReflectionAttribute, isRepeated)
7493
47
{
7494
47
  const reflection_object *intern;
7495
47
  const attribute_reference *attr;
7496
7497
47
  ZEND_PARSE_PARAMETERS_NONE();
7498
44
  GET_REFLECTION_OBJECT_PTR(attr);
7499
7500
44
  RETURN_BOOL(zend_is_attribute_repeated(attr->attributes, attr->data));
7501
44
}
7502
/* }}} */
7503
7504
/* {{{ Returns the arguments passed to the attribute */
7505
ZEND_METHOD(ReflectionAttribute, getArguments)
7506
545
{
7507
545
  const reflection_object *intern;
7508
545
  const attribute_reference *attr;
7509
7510
545
  ZEND_PARSE_PARAMETERS_NONE();
7511
545
  GET_REFLECTION_OBJECT_PTR(attr);
7512
7513
545
  if (attr->data->argc == 0) {
7514
47
    RETURN_EMPTY_ARRAY();
7515
47
  }
7516
7517
498
  array_init(return_value);
7518
7519
498
  zval tmp;
7520
1.24k
  for (uint32_t i = 0; i < attr->data->argc; i++) {
7521
758
    if (FAILURE == zend_get_attribute_value(&tmp, attr->data, i, attr->scope)) {
7522
15
      RETURN_THROWS();
7523
15
    }
7524
7525
743
    if (attr->data->args[i].name) {
7526
      /* We ensured at compile-time that there are no duplicate parameter names. */
7527
44
      zend_hash_add_new(Z_ARRVAL_P(return_value), attr->data->args[i].name, &tmp);
7528
699
    } else {
7529
699
      add_next_index_zval(return_value, &tmp);
7530
699
    }
7531
743
  }
7532
498
}
7533
/* }}} */
7534
7535
/* {{{ Returns the attribute as an object */
7536
ZEND_METHOD(ReflectionAttribute, newInstance)
7537
518
{
7538
518
  const reflection_object *intern;
7539
518
  const attribute_reference *attr;
7540
7541
518
  ZEND_PARSE_PARAMETERS_NONE();
7542
7543
518
  GET_REFLECTION_OBJECT_PTR(attr);
7544
7545
518
  zend_class_entry *ce;
7546
518
  if (NULL == (ce = zend_lookup_class(attr->data->name))) {
7547
20
    zend_throw_error(NULL, "Attribute class \"%pS\" not found", attr->data->name);
7548
20
    RETURN_THROWS();
7549
20
  }
7550
7551
498
  zend_attribute *marker;
7552
498
  if (NULL == (marker = zend_get_attribute_str(ce->attributes, ZEND_STRL("attribute")))) {
7553
11
    zend_throw_error(NULL, "Attempting to use non-attribute class \"%pS\" as attribute", attr->data->name);
7554
11
    RETURN_THROWS();
7555
11
  }
7556
7557
  /* This code can be reached under one of three possible conditions:
7558
   * - the attribute is an internal attribute, and it had the target and
7559
   *   and repetition validated already
7560
   * - the attribute is an internal attribute and repetition was validated
7561
   *   already, the internal validator might have been run if the target was
7562
   *   correct, but any error would have been stored in
7563
   *   `zend_attribute.validation_error` instead of being thrown due to the
7564
   *   presence of #[DelayedTargetValidation]
7565
   * - the attribute is a user attribute, and neither target nor repetition
7566
   *   have been validated.
7567
   */
7568
487
  uint32_t flags = zend_attribute_attribute_get_flags(marker, ce);
7569
487
  if (EG(exception)) {
7570
20
    RETURN_THROWS();
7571
20
  }
7572
7573
  /* No harm in always running target validation, for internal attributes
7574
   * without #[DelayedTargetValidation] it isn't necessary but will always
7575
   * succeed. */
7576
467
  if (!(attr->target & flags)) {
7577
117
    zend_string *location = zend_get_attribute_target_names(attr->target);
7578
117
    zend_string *allowed = zend_get_attribute_target_names(flags);
7579
7580
117
    zend_throw_error(NULL, "Attribute \"%pS\" cannot target %pS (allowed targets: %pS)",
7581
117
      attr->data->name, location, allowed
7582
117
    );
7583
7584
117
    zend_string_release(location);
7585
117
    zend_string_release(allowed);
7586
7587
117
    RETURN_THROWS();
7588
117
  }
7589
7590
350
  if (attr->data->validation_error != NULL) {
7591
    /* Delayed validation errors should only be set for internal attributes. */
7592
97
    ZEND_ASSERT(ce->type == ZEND_INTERNAL_CLASS);
7593
    /* Delayed validation errors should only be set when
7594
     * #[\DelayedTargetValidation] is used. Searching for the attribute is
7595
     * more expensive than just an assertion and so we don't worry about it
7596
     * for non-debug builds. See discussion on GH-18817. */
7597
97
#if ZEND_DEBUG
7598
97
    const zend_attribute *delayed_target_validation = zend_get_attribute_str(
7599
97
      attr->attributes,
7600
97
      "delayedtargetvalidation",
7601
97
      strlen("delayedtargetvalidation")
7602
97
    );
7603
97
    ZEND_ASSERT(delayed_target_validation != NULL);
7604
97
#endif
7605
97
    zend_throw_exception(zend_ce_error, ZSTR_VAL(attr->data->validation_error), 0);
7606
97
    RETURN_THROWS();
7607
97
  }
7608
7609
  /* Repetition validation is done even if #[DelayedTargetValidation] is used
7610
   * and so can be skipped for internal attributes. */
7611
253
  if (ce->type == ZEND_USER_CLASS
7612
238
    && !(flags & ZEND_ATTRIBUTE_IS_REPEATABLE)
7613
191
    && zend_is_attribute_repeated(attr->attributes, attr->data)
7614
253
  ) {
7615
15
    zend_throw_error(NULL, "Attribute \"%pS\" must not be repeated", attr->data->name);
7616
15
    RETURN_THROWS();
7617
15
  }
7618
7619
238
  zval obj;
7620
7621
238
  if (SUCCESS != zend_get_attribute_object(&obj, ce, attr->data, attr->scope, attr->filename)) {
7622
39
    RETURN_THROWS();
7623
39
  }
7624
7625
199
  RETURN_COPY_VALUE(&obj);
7626
199
}
7627
7628
ZEND_METHOD(ReflectionEnum, __construct)
7629
50
{
7630
50
  reflection_class_object_ctor(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
7631
50
  if (EG(exception)) {
7632
9
    RETURN_THROWS();
7633
9
  }
7634
7635
41
  const reflection_object *intern;
7636
41
  const zend_class_entry *ce;
7637
41
  GET_REFLECTION_OBJECT_PTR(ce);
7638
7639
41
  if (!(ce->ce_flags & ZEND_ACC_ENUM)) {
7640
0
    zend_throw_exception_ex(reflection_exception_ptr, -1, "Class \"%pS\" is not an enum", ce->name);
7641
0
    RETURN_THROWS();
7642
0
  }
7643
41
}
7644
7645
ZEND_METHOD(ReflectionEnum, hasCase)
7646
8
{
7647
8
  const reflection_object *intern;
7648
8
  const zend_class_entry *ce;
7649
8
  zend_string *name;
7650
7651
8
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
7652
0
    RETURN_THROWS();
7653
0
  }
7654
7655
8
  GET_REFLECTION_OBJECT_PTR(ce);
7656
7657
8
  const zend_class_constant *class_const = zend_hash_find_ptr(&ce->constants_table, name);
7658
8
  if (class_const == NULL) {
7659
4
    RETURN_FALSE;
7660
4
  }
7661
7662
4
  RETURN_BOOL(ZEND_CLASS_CONST_FLAGS(class_const) & ZEND_CLASS_CONST_IS_CASE);
7663
4
}
7664
7665
ZEND_METHOD(ReflectionEnum, getCase)
7666
1
{
7667
1
  const reflection_object *intern;
7668
1
  const zend_class_entry *ce;
7669
1
  zend_string *name;
7670
7671
1
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name) == FAILURE) {
7672
0
    RETURN_THROWS();
7673
0
  }
7674
7675
1
  GET_REFLECTION_OBJECT_PTR(ce);
7676
7677
1
  zend_class_constant *constant = zend_hash_find_ptr(CE_CONSTANTS_TABLE(ce), name);
7678
1
  if (constant == NULL) {
7679
1
    zend_throw_exception_ex(reflection_exception_ptr, 0, "Case %pS::%pS does not exist", ce->name, name);
7680
1
    RETURN_THROWS();
7681
1
  }
7682
0
  if (!(ZEND_CLASS_CONST_FLAGS(constant) & ZEND_CLASS_CONST_IS_CASE)) {
7683
0
    zend_throw_exception_ex(reflection_exception_ptr, 0, "%pS::%pS is not a case", ce->name, name);
7684
0
    RETURN_THROWS();
7685
0
  }
7686
7687
0
  reflection_enum_case_factory(ce, name, constant, return_value);
7688
0
}
7689
7690
ZEND_METHOD(ReflectionEnum, getCases)
7691
3
{
7692
3
  const reflection_object *intern;
7693
3
  const zend_class_entry *ce;
7694
7695
3
  ZEND_PARSE_PARAMETERS_NONE();
7696
7697
2
  GET_REFLECTION_OBJECT_PTR(ce);
7698
7699
2
  array_init(return_value);
7700
16
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(CE_CONSTANTS_TABLE(ce), zend_string *name, zend_class_constant *constant) {
7701
16
    if (ZEND_CLASS_CONST_FLAGS(constant) & ZEND_CLASS_CONST_IS_CASE) {
7702
4
      zval class_const;
7703
4
      reflection_enum_case_factory(ce, name, constant, &class_const);
7704
4
      zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &class_const);
7705
4
    }
7706
16
  } ZEND_HASH_FOREACH_END();
7707
2
}
7708
7709
ZEND_METHOD(ReflectionEnum, isBacked)
7710
6
{
7711
6
  const reflection_object *intern;
7712
6
  const zend_class_entry *ce;
7713
7714
6
  ZEND_PARSE_PARAMETERS_NONE();
7715
7716
6
  GET_REFLECTION_OBJECT_PTR(ce);
7717
6
  RETURN_BOOL(ce->enum_backing_type != IS_UNDEF);
7718
6
}
7719
7720
ZEND_METHOD(ReflectionEnum, getBackingType)
7721
5
{
7722
5
  const reflection_object *intern;
7723
5
  const zend_class_entry *ce;
7724
7725
5
  ZEND_PARSE_PARAMETERS_NONE();
7726
7727
5
  GET_REFLECTION_OBJECT_PTR(ce);
7728
7729
5
  if (ce->enum_backing_type == IS_UNDEF) {
7730
2
    RETURN_NULL();
7731
3
  } else {
7732
3
    zend_type type = ZEND_TYPE_INIT_CODE(ce->enum_backing_type, false, 0);
7733
3
    reflection_type_factory(type, return_value, false);
7734
3
  }
7735
5
}
7736
7737
ZEND_METHOD(ReflectionEnumUnitCase, __construct)
7738
14
{
7739
14
  ZEND_MN(ReflectionClassConstant___construct)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
7740
14
  if (EG(exception)) {
7741
9
    RETURN_THROWS();
7742
9
  }
7743
7744
5
  const reflection_object *intern;
7745
5
  const zend_class_constant *ref;
7746
7747
5
  GET_REFLECTION_OBJECT_PTR(ref);
7748
7749
5
  if (!(ZEND_CLASS_CONST_FLAGS(ref) & ZEND_CLASS_CONST_IS_CASE)) {
7750
0
    const zval *case_name = reflection_prop_name(ZEND_THIS);
7751
0
    zend_throw_exception_ex(reflection_exception_ptr, 0, "Constant %pS::%pS is not a case", ref->ce->name, Z_STR_P(case_name));
7752
0
    RETURN_THROWS();
7753
0
  }
7754
5
}
7755
7756
ZEND_METHOD(ReflectionEnumUnitCase, getEnum)
7757
1
{
7758
1
  const reflection_object *intern;
7759
1
  const zend_class_constant *ref;
7760
7761
1
  ZEND_PARSE_PARAMETERS_NONE();
7762
1
  GET_REFLECTION_OBJECT_PTR(ref);
7763
7764
1
  zend_reflection_class_factory(ref->ce, return_value);
7765
1
}
7766
7767
ZEND_METHOD(ReflectionEnumBackedCase, __construct)
7768
8
{
7769
8
  ZEND_MN(ReflectionEnumUnitCase___construct)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
7770
8
  if (EG(exception)) {
7771
5
    RETURN_THROWS();
7772
5
  }
7773
7774
3
  const reflection_object *intern;
7775
3
  const zend_class_constant *ref;
7776
7777
3
  GET_REFLECTION_OBJECT_PTR(ref);
7778
7779
3
  if (ref->ce->enum_backing_type == IS_UNDEF) {
7780
0
    const zval *case_name = reflection_prop_name(ZEND_THIS);
7781
0
    zend_throw_exception_ex(reflection_exception_ptr, 0, "Enum case %pS::%pS is not a backed case", ref->ce->name, Z_STR_P(case_name));
7782
0
    RETURN_THROWS();
7783
0
  }
7784
3
}
7785
7786
ZEND_METHOD(ReflectionEnumBackedCase, getBackingValue)
7787
3
{
7788
3
  const reflection_object *intern;
7789
3
  zend_class_constant *ref;
7790
7791
3
  ZEND_PARSE_PARAMETERS_NONE();
7792
3
  GET_REFLECTION_OBJECT_PTR(ref);
7793
7794
3
  if (Z_TYPE(ref->value) == IS_CONSTANT_AST) {
7795
2
    zval_update_constant_ex(&ref->value, ref->ce);
7796
2
    if (EG(exception)) {
7797
2
      RETURN_THROWS();
7798
2
    }
7799
2
  }
7800
7801
1
  ZEND_ASSERT(intern->ce->enum_backing_type != IS_UNDEF);
7802
1
  const zval *member_p = zend_enum_fetch_case_value(Z_OBJ(ref->value));
7803
7804
1
  ZVAL_COPY_OR_DUP(return_value, member_p);
7805
1
}
7806
7807
/* {{{ proto ReflectionFiber::__construct(Fiber $fiber) */
7808
ZEND_METHOD(ReflectionFiber, __construct)
7809
12
{
7810
12
  zval *fiber;
7811
7812
12
  zval *object = ZEND_THIS;
7813
12
  reflection_object *intern = Z_REFLECTION_P(object);
7814
7815
32
  ZEND_PARSE_PARAMETERS_START(1, 1)
7816
32
    Z_PARAM_OBJECT_OF_CLASS(fiber, zend_ce_fiber)
7817
12
  ZEND_PARSE_PARAMETERS_END();
7818
7819
7
  if (intern->ce) {
7820
0
    zval_ptr_dtor(&intern->obj);
7821
0
  }
7822
7823
7
  intern->ref_type = REF_TYPE_FIBER;
7824
7
  ZVAL_OBJ_COPY(&intern->obj, Z_OBJ_P(fiber));
7825
7
  intern->ce = zend_ce_fiber;
7826
7
}
7827
/* }}} */
7828
7829
ZEND_METHOD(ReflectionFiber, getFiber)
7830
0
{
7831
0
  ZEND_PARSE_PARAMETERS_NONE();
7832
7833
0
  RETURN_OBJ_COPY(Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj));
7834
0
}
7835
7836
11
#define REFLECTION_CHECK_VALID_FIBER(fiber) do { \
7837
11
    if (fiber == NULL || fiber->context.status == ZEND_FIBER_STATUS_INIT || fiber->context.status == ZEND_FIBER_STATUS_DEAD) { \
7838
0
      zend_throw_error(NULL, "Cannot fetch information from a fiber that has not been started or is terminated"); \
7839
0
      RETURN_THROWS(); \
7840
0
    } \
7841
11
  } while (0)
7842
7843
ZEND_METHOD(ReflectionFiber, getTrace)
7844
6
{
7845
6
  zend_fiber *fiber = (zend_fiber *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
7846
6
  zend_long options = DEBUG_BACKTRACE_PROVIDE_OBJECT;
7847
7848
18
  ZEND_PARSE_PARAMETERS_START(0, 1)
7849
18
    Z_PARAM_OPTIONAL
7850
18
    Z_PARAM_LONG(options);
7851
6
  ZEND_PARSE_PARAMETERS_END();
7852
7853
6
  REFLECTION_CHECK_VALID_FIBER(fiber);
7854
7855
6
  zend_execute_data *prev_execute_data = fiber->stack_bottom->prev_execute_data;
7856
6
  fiber->stack_bottom->prev_execute_data = NULL;
7857
7858
6
  if (EG(active_fiber) != fiber) {
7859
    // No need to replace current execute data if within the current fiber.
7860
6
    EG(current_execute_data) = fiber->execute_data;
7861
6
  }
7862
7863
6
  zend_fetch_debug_backtrace(return_value, 0, options, 0);
7864
7865
6
  EG(current_execute_data) = execute_data; // Restore original execute data.
7866
6
  fiber->stack_bottom->prev_execute_data = prev_execute_data; // Restore prev execute data on fiber stack.
7867
6
}
7868
7869
ZEND_METHOD(ReflectionFiber, getExecutingLine)
7870
2
{
7871
2
  const zend_fiber *fiber = (const zend_fiber *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
7872
7873
2
  ZEND_PARSE_PARAMETERS_NONE();
7874
7875
2
  REFLECTION_CHECK_VALID_FIBER(fiber);
7876
7877
2
  zend_execute_data *prev_execute_data;
7878
2
  if (EG(active_fiber) == fiber) {
7879
0
    prev_execute_data = execute_data->prev_execute_data;
7880
2
  } else {
7881
2
    prev_execute_data = fiber->execute_data->prev_execute_data;
7882
2
  }
7883
7884
4
  while (prev_execute_data && (!prev_execute_data->func || !ZEND_USER_CODE(prev_execute_data->func->common.type))) {
7885
2
    prev_execute_data = prev_execute_data->prev_execute_data;
7886
2
  }
7887
2
  if (prev_execute_data && prev_execute_data->func && ZEND_USER_CODE(prev_execute_data->func->common.type)) {
7888
1
    RETURN_LONG(prev_execute_data->opline->lineno);
7889
1
  }
7890
1
  RETURN_NULL();
7891
1
}
7892
7893
ZEND_METHOD(ReflectionFiber, getExecutingFile)
7894
3
{
7895
3
  const zend_fiber *fiber = (const zend_fiber *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
7896
7897
3
  ZEND_PARSE_PARAMETERS_NONE();
7898
7899
3
  REFLECTION_CHECK_VALID_FIBER(fiber);
7900
7901
3
  zend_execute_data *prev_execute_data;
7902
3
  if (EG(active_fiber) == fiber) {
7903
0
    prev_execute_data = execute_data->prev_execute_data;
7904
3
  } else {
7905
3
    prev_execute_data = fiber->execute_data->prev_execute_data;
7906
3
  }
7907
7908
6
  while (prev_execute_data && (!prev_execute_data->func || !ZEND_USER_CODE(prev_execute_data->func->common.type))) {
7909
3
    prev_execute_data = prev_execute_data->prev_execute_data;
7910
3
  }
7911
3
  if (prev_execute_data && prev_execute_data->func && ZEND_USER_CODE(prev_execute_data->func->common.type)) {
7912
2
    RETURN_STR_COPY(prev_execute_data->func->op_array.filename);
7913
2
  }
7914
1
  RETURN_NULL();
7915
1
}
7916
7917
ZEND_METHOD(ReflectionFiber, getCallable)
7918
0
{
7919
0
  const zend_fiber *fiber = (const zend_fiber *) Z_OBJ(Z_REFLECTION_P(ZEND_THIS)->obj);
7920
7921
0
  ZEND_PARSE_PARAMETERS_NONE();
7922
7923
0
  if (fiber == NULL || fiber->context.status == ZEND_FIBER_STATUS_DEAD) {
7924
0
    zend_throw_error(NULL, "Cannot fetch the callable from a fiber that has terminated");
7925
0
    RETURN_THROWS();
7926
0
  }
7927
7928
0
  RETURN_COPY(&fiber->fci.function_name);
7929
0
}
7930
7931
/* {{{ _reflection_write_property */
7932
static zval *_reflection_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot)
7933
148
{
7934
148
  if (zend_hash_exists(&object->ce->properties_info, name)
7935
0
    && (zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_NAME)) || zend_string_equals(name, ZSTR_KNOWN(ZEND_STR_CLASS))))
7936
0
  {
7937
0
    zend_throw_exception_ex(reflection_exception_ptr, 0,
7938
0
      "Cannot set read-only property %pS::$%pS", object->ce->name, name);
7939
0
    return &EG(uninitialized_zval);
7940
148
  } else {
7941
148
    return zend_std_write_property(object, name, value, cache_slot);
7942
148
  }
7943
148
}
7944
/* }}} */
7945
7946
ZEND_METHOD(ReflectionConstant, __construct)
7947
88
{
7948
88
  zend_string *name;
7949
7950
88
  zval *object = ZEND_THIS;
7951
88
  reflection_object *intern = Z_REFLECTION_P(object);
7952
7953
260
  ZEND_PARSE_PARAMETERS_START(1, 1)
7954
336
    Z_PARAM_STR(name)
7955
88
  ZEND_PARSE_PARAMETERS_END();
7956
7957
  /* Build name with lowercased ns. */
7958
88
  bool backslash_prefixed = ZSTR_VAL(name)[0] == '\\';
7959
84
  const char *source = ZSTR_VAL(name) + backslash_prefixed;
7960
84
  size_t source_len = ZSTR_LEN(name) - backslash_prefixed;
7961
84
  zend_string *lc_name = zend_string_alloc(source_len, /* persistent */ false);
7962
84
  const char *ns_end = zend_memrchr(source, '\\', source_len);
7963
84
  size_t ns_len = 0;
7964
84
  if (ns_end) {
7965
8
    ns_len = ns_end - ZSTR_VAL(name);
7966
8
    zend_str_tolower_copy(ZSTR_VAL(lc_name), source, ns_len);
7967
8
  }
7968
84
  memcpy(ZSTR_VAL(lc_name) + ns_len, source + ns_len, source_len - ns_len);
7969
7970
84
  zend_constant *const_ = zend_get_constant_ptr(lc_name);
7971
84
  zend_string_release_ex(lc_name, /* persistent */ false);
7972
84
  if (!const_) {
7973
8
    zend_throw_exception_ex(reflection_exception_ptr, 0, "Constant \"%pS\" does not exist", name);
7974
8
    RETURN_THROWS();
7975
8
  }
7976
7977
76
  intern->ptr = const_;
7978
76
  intern->ref_type = REF_TYPE_OTHER;
7979
7980
76
  zval *name_zv = reflection_prop_name(object);
7981
76
  zval_ptr_dtor(name_zv);
7982
76
  ZVAL_STR_COPY(name_zv, name);
7983
76
}
7984
7985
ZEND_METHOD(ReflectionConstant, getName)
7986
1
{
7987
1
  const reflection_object *intern;
7988
1
  const zend_constant *const_;
7989
7990
1
  ZEND_PARSE_PARAMETERS_NONE();
7991
7992
1
  GET_REFLECTION_OBJECT_PTR(const_);
7993
1
  RETURN_STR_COPY(const_->name);
7994
1
}
7995
7996
ZEND_METHOD(ReflectionConstant, inNamespace)
7997
0
{
7998
0
  const reflection_object *intern;
7999
0
  const zend_constant *const_;
8000
8001
0
  ZEND_PARSE_PARAMETERS_NONE();
8002
8003
0
  GET_REFLECTION_OBJECT_PTR(const_);
8004
8005
0
  const char *backslash = zend_memrchr(ZSTR_VAL(const_->name), '\\', ZSTR_LEN(const_->name));
8006
0
  RETURN_BOOL(backslash);
8007
0
}
8008
/* }}} */
8009
8010
ZEND_METHOD(ReflectionConstant, getNamespaceName)
8011
0
{
8012
0
  const reflection_object *intern;
8013
0
  const zend_constant *const_;
8014
8015
0
  ZEND_PARSE_PARAMETERS_NONE();
8016
8017
0
  GET_REFLECTION_OBJECT_PTR(const_);
8018
8019
0
  const char *backslash = zend_memrchr(ZSTR_VAL(const_->name), '\\', ZSTR_LEN(const_->name));
8020
0
  if (backslash) {
8021
0
    size_t length = backslash - ZSTR_VAL(const_->name);
8022
0
    RETURN_STRINGL(ZSTR_VAL(const_->name), length);
8023
0
  } else {
8024
0
    RETURN_EMPTY_STRING();
8025
0
  }
8026
0
}
8027
8028
ZEND_METHOD(ReflectionConstant, getShortName)
8029
0
{
8030
0
  const reflection_object *intern;
8031
0
  const zend_constant *const_;
8032
8033
0
  ZEND_PARSE_PARAMETERS_NONE();
8034
8035
0
  GET_REFLECTION_OBJECT_PTR(const_);
8036
8037
0
  const char *backslash = zend_memrchr(ZSTR_VAL(const_->name), '\\', ZSTR_LEN(const_->name));
8038
0
  if (backslash) {
8039
0
    size_t prefix = backslash - ZSTR_VAL(const_->name) + 1;
8040
0
    size_t length = ZSTR_LEN(const_->name) - prefix;
8041
0
    RETURN_STRINGL(ZSTR_VAL(const_->name) + prefix, length);
8042
0
  } else {
8043
0
    RETURN_STR_COPY(const_->name);
8044
0
  }
8045
0
}
8046
8047
ZEND_METHOD(ReflectionConstant, getValue)
8048
2
{
8049
2
  const reflection_object *intern;
8050
2
  const zend_constant *const_;
8051
8052
2
  ZEND_PARSE_PARAMETERS_NONE();
8053
8054
2
  GET_REFLECTION_OBJECT_PTR(const_);
8055
2
  RETURN_COPY(&const_->value);
8056
2
}
8057
8058
ZEND_METHOD(ReflectionConstant, isDeprecated)
8059
1
{
8060
1
  const reflection_object *intern;
8061
1
  const zend_constant *const_;
8062
8063
1
  ZEND_PARSE_PARAMETERS_NONE();
8064
8065
1
  GET_REFLECTION_OBJECT_PTR(const_);
8066
1
  RETURN_BOOL(ZEND_CONSTANT_FLAGS(const_) & CONST_DEPRECATED);
8067
1
}
8068
8069
ZEND_METHOD(ReflectionConstant, getFileName)
8070
0
{
8071
0
  const reflection_object *intern;
8072
0
  const zend_constant *const_;
8073
8074
0
  ZEND_PARSE_PARAMETERS_NONE();
8075
8076
0
  GET_REFLECTION_OBJECT_PTR(const_);
8077
0
  if (const_->filename != NULL) {
8078
0
    RETURN_STR_COPY(const_->filename);
8079
0
  }
8080
0
  RETURN_FALSE;
8081
0
}
8082
8083
static void reflection_constant_find_ext(INTERNAL_FUNCTION_PARAMETERS, bool only_name)
8084
0
{
8085
0
  const reflection_object *intern;
8086
0
  const zend_constant *const_;
8087
8088
0
  ZEND_PARSE_PARAMETERS_NONE();
8089
8090
0
  GET_REFLECTION_OBJECT_PTR(const_);
8091
0
  uint32_t module_number = ZEND_CONSTANT_MODULE_NUMBER(const_);
8092
0
  if (module_number == PHP_USER_CONSTANT) {
8093
    // For user constants, ReflectionConstant::getExtension() returns null,
8094
    // ReflectionConstant::getExtensionName() returns false
8095
0
    if (only_name) {
8096
0
      RETURN_FALSE;
8097
0
    }
8098
0
    RETURN_NULL();
8099
0
  }
8100
0
  ZEND_HASH_MAP_FOREACH_PTR(&module_registry, zend_module_entry *module) {
8101
0
    if (module->module_number != module_number) {
8102
0
      continue;
8103
0
    }
8104
0
    if (only_name) {
8105
0
      RETURN_STRING(module->name);
8106
0
    }
8107
0
    reflection_extension_factory(return_value, module);
8108
0
    return;
8109
0
  } ZEND_HASH_FOREACH_END();
8110
8111
0
  zend_throw_exception_ex(
8112
0
    reflection_exception_ptr,
8113
0
    0,
8114
0
    "Unable to locate extension with module_number %" PRIu32 " that provides constant %pS",
8115
0
    module_number,
8116
0
    const_->name
8117
0
  );
8118
0
  RETURN_THROWS();
8119
0
}
8120
8121
/* {{{ Returns NULL or the extension the constant belongs to */
8122
ZEND_METHOD(ReflectionConstant, getExtension)
8123
0
{
8124
0
  reflection_constant_find_ext(INTERNAL_FUNCTION_PARAM_PASSTHRU, false);
8125
0
}
8126
/* }}} */
8127
8128
/* {{{ Returns false or the name of the extension the constant belongs to */
8129
ZEND_METHOD(ReflectionConstant, getExtensionName)
8130
0
{
8131
0
  reflection_constant_find_ext(INTERNAL_FUNCTION_PARAM_PASSTHRU, true);
8132
0
}
8133
/* }}} */
8134
8135
ZEND_METHOD(ReflectionConstant, getAttributes)
8136
66
{
8137
66
  const reflection_object *intern;
8138
66
  const zend_constant *const_;
8139
8140
66
  GET_REFLECTION_OBJECT_PTR(const_);
8141
8142
66
  reflect_attributes(INTERNAL_FUNCTION_PARAM_PASSTHRU,
8143
66
    const_->attributes, 0, NULL, ZEND_ATTRIBUTE_TARGET_CONST,
8144
66
    const_->filename);
8145
66
}
8146
8147
ZEND_METHOD(ReflectionConstant, __toString)
8148
13
{
8149
13
  const reflection_object *intern;
8150
13
  const zend_constant *const_;
8151
13
  smart_str str = {0};
8152
8153
13
  ZEND_PARSE_PARAMETERS_NONE();
8154
8155
13
  GET_REFLECTION_OBJECT_PTR(const_);
8156
13
  _const_string(&str, const_->name, &const_->value, "");
8157
13
  RETURN_STR(smart_str_extract(&str));
8158
13
}
8159
8160
PHP_MINIT_FUNCTION(reflection) /* {{{ */
8161
16
{
8162
16
  memcpy(&reflection_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
8163
16
  reflection_object_handlers.offset = offsetof(reflection_object, zo);
8164
16
  reflection_object_handlers.free_obj = reflection_free_objects_storage;
8165
16
  reflection_object_handlers.clone_obj = NULL;
8166
16
  reflection_object_handlers.write_property = _reflection_write_property;
8167
16
  reflection_object_handlers.get_gc = reflection_get_gc;
8168
8169
16
  reflection_exception_ptr = register_class_ReflectionException(zend_ce_exception);
8170
8171
16
  reflection_ptr = register_class_Reflection();
8172
8173
16
  reflector_ptr = register_class_Reflector(zend_ce_stringable);
8174
8175
16
  reflection_function_abstract_ptr = register_class_ReflectionFunctionAbstract(reflector_ptr);
8176
16
  reflection_function_abstract_ptr->default_object_handlers = &reflection_object_handlers;
8177
16
  reflection_function_abstract_ptr->create_object = reflection_objects_new;
8178
8179
16
  reflection_function_ptr = register_class_ReflectionFunction(reflection_function_abstract_ptr);
8180
16
  reflection_function_ptr->create_object = reflection_objects_new;
8181
16
  reflection_function_ptr->default_object_handlers = &reflection_object_handlers;
8182
8183
16
  reflection_generator_ptr = register_class_ReflectionGenerator();
8184
16
  reflection_generator_ptr->create_object = reflection_objects_new;
8185
16
  reflection_generator_ptr->default_object_handlers = &reflection_object_handlers;
8186
8187
16
  reflection_parameter_ptr = register_class_ReflectionParameter(reflector_ptr);
8188
16
  reflection_parameter_ptr->create_object = reflection_objects_new;
8189
16
  reflection_parameter_ptr->default_object_handlers = &reflection_object_handlers;
8190
8191
16
  reflection_type_ptr = register_class_ReflectionType(zend_ce_stringable);
8192
16
  reflection_type_ptr->create_object = reflection_objects_new;
8193
16
  reflection_type_ptr->default_object_handlers = &reflection_object_handlers;
8194
8195
16
  reflection_named_type_ptr = register_class_ReflectionNamedType(reflection_type_ptr);
8196
16
  reflection_named_type_ptr->create_object = reflection_objects_new;
8197
16
  reflection_named_type_ptr->default_object_handlers = &reflection_object_handlers;
8198
8199
16
  reflection_union_type_ptr = register_class_ReflectionUnionType(reflection_type_ptr);
8200
16
  reflection_union_type_ptr->create_object = reflection_objects_new;
8201
16
  reflection_union_type_ptr->default_object_handlers = &reflection_object_handlers;
8202
8203
16
  reflection_intersection_type_ptr = register_class_ReflectionIntersectionType(reflection_type_ptr);
8204
16
  reflection_intersection_type_ptr->create_object = reflection_objects_new;
8205
16
  reflection_intersection_type_ptr->default_object_handlers = &reflection_object_handlers;
8206
8207
16
  reflection_method_ptr = register_class_ReflectionMethod(reflection_function_abstract_ptr);
8208
16
  reflection_method_ptr->create_object = reflection_objects_new;
8209
16
  reflection_method_ptr->default_object_handlers = &reflection_object_handlers;
8210
8211
16
  reflection_class_ptr = register_class_ReflectionClass(reflector_ptr);
8212
16
  reflection_class_ptr->create_object = reflection_objects_new;
8213
16
  reflection_class_ptr->default_object_handlers = &reflection_object_handlers;
8214
8215
16
  reflection_object_ptr = register_class_ReflectionObject(reflection_class_ptr);
8216
16
  reflection_object_ptr->create_object = reflection_objects_new;
8217
16
  reflection_object_ptr->default_object_handlers = &reflection_object_handlers;
8218
8219
16
  reflection_property_ptr = register_class_ReflectionProperty(reflector_ptr);
8220
16
  reflection_property_ptr->create_object = reflection_objects_new;
8221
16
  reflection_property_ptr->default_object_handlers = &reflection_object_handlers;
8222
8223
16
  reflection_class_constant_ptr = register_class_ReflectionClassConstant(reflector_ptr);
8224
16
  reflection_class_constant_ptr->create_object = reflection_objects_new;
8225
16
  reflection_class_constant_ptr->default_object_handlers = &reflection_object_handlers;
8226
8227
16
  reflection_extension_ptr = register_class_ReflectionExtension(reflector_ptr);
8228
16
  reflection_extension_ptr->create_object = reflection_objects_new;
8229
16
  reflection_extension_ptr->default_object_handlers = &reflection_object_handlers;
8230
8231
16
  reflection_zend_extension_ptr = register_class_ReflectionZendExtension(reflector_ptr);
8232
16
  reflection_zend_extension_ptr->create_object = reflection_objects_new;
8233
16
  reflection_zend_extension_ptr->default_object_handlers = &reflection_object_handlers;
8234
8235
16
  reflection_reference_ptr = register_class_ReflectionReference();
8236
16
  reflection_reference_ptr->create_object = reflection_objects_new;
8237
16
  reflection_reference_ptr->default_object_handlers = &reflection_object_handlers;
8238
8239
16
  reflection_attribute_ptr = register_class_ReflectionAttribute(reflector_ptr);
8240
16
  reflection_attribute_ptr->create_object = reflection_objects_new;
8241
16
  reflection_attribute_ptr->default_object_handlers = &reflection_object_handlers;
8242
8243
16
  reflection_enum_ptr = register_class_ReflectionEnum(reflection_class_ptr);
8244
16
  reflection_enum_ptr->create_object = reflection_objects_new;
8245
16
  reflection_enum_ptr->default_object_handlers = &reflection_object_handlers;
8246
8247
16
  reflection_enum_unit_case_ptr = register_class_ReflectionEnumUnitCase(reflection_class_constant_ptr);
8248
16
  reflection_enum_unit_case_ptr->create_object = reflection_objects_new;
8249
16
  reflection_enum_unit_case_ptr->default_object_handlers = &reflection_object_handlers;
8250
8251
16
  reflection_enum_backed_case_ptr = register_class_ReflectionEnumBackedCase(reflection_enum_unit_case_ptr);
8252
16
  reflection_enum_backed_case_ptr->create_object = reflection_objects_new;
8253
16
  reflection_enum_backed_case_ptr->default_object_handlers = &reflection_object_handlers;
8254
8255
16
  reflection_fiber_ptr = register_class_ReflectionFiber();
8256
16
  reflection_fiber_ptr->create_object = reflection_objects_new;
8257
16
  reflection_fiber_ptr->default_object_handlers = &reflection_object_handlers;
8258
8259
16
  reflection_constant_ptr = register_class_ReflectionConstant(reflector_ptr);
8260
16
  reflection_constant_ptr->create_object = reflection_objects_new;
8261
16
  reflection_constant_ptr->default_object_handlers = &reflection_object_handlers;
8262
8263
16
  reflection_property_hook_type_ptr = register_class_PropertyHookType();
8264
8265
16
  REFLECTION_G(key_initialized) = false;
8266
8267
16
  return SUCCESS;
8268
16
} /* }}} */
8269
8270
PHP_MINFO_FUNCTION(reflection) /* {{{ */
8271
16
{
8272
16
  php_info_print_table_start();
8273
16
  php_info_print_table_row(2, "Reflection", "enabled");
8274
16
  php_info_print_table_end();
8275
16
} /* }}} */
8276
8277
zend_module_entry reflection_module_entry = { /* {{{ */
8278
  STANDARD_MODULE_HEADER,
8279
  "Reflection",
8280
  NULL,
8281
  PHP_MINIT(reflection),
8282
  NULL,
8283
  NULL,
8284
  NULL,
8285
  PHP_MINFO(reflection),
8286
  PHP_REFLECTION_VERSION,
8287
  ZEND_MODULE_GLOBALS(reflection),
8288
  NULL,
8289
  NULL,
8290
  NULL,
8291
  STANDARD_MODULE_PROPERTIES_EX
8292
}; /* }}} */