Coverage Report

Created: 2025-12-31 07:28

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