Coverage Report

Created: 2026-07-25 06:39

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