Coverage Report

Created: 2025-11-16 06:23

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