Coverage Report

Created: 2025-12-14 06:10

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