Coverage Report

Created: 2025-12-14 06:05

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