Coverage Report

Created: 2026-04-01 06:49

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