Coverage Report

Created: 2026-10-28 06:20

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