Coverage Report

Created: 2025-06-13 06:43

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