Coverage Report

Created: 2025-07-23 06:33

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