Coverage Report

Created: 2025-09-27 06:26

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