Coverage Report

Created: 2026-06-02 06:39

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