Skip to content

Commit 6c4f630

Browse files
committed
Do not preserve BC for self/parent and always resolve when possible
1 parent 8969b8d commit 6c4f630

File tree

41 files changed

+394
-779
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+394
-779
lines changed

Zend/tests/type_declarations/intersection_types/invalid_types/invalid_parent_type.phpt renamed to Zend/tests/type_declarations/intersection_types/invalid_types/invalid_unresolved_relative_type_parent.phpt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
--TEST--
2-
parent type cannot take part in an intersection type
2+
parent type cannot take part in an intersection type when unresolved
33
--FILE--
44
<?php
55

6-
class A {}
7-
8-
class B extends A {
6+
trait T {
97
public function foo(): parent&Iterator {}
108
}
119

Zend/tests/type_declarations/intersection_types/invalid_types/invalid_self_type.phpt renamed to Zend/tests/type_declarations/intersection_types/invalid_types/invalid_unresolved_relative_type_self.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
--TEST--
2-
self type cannot take part in an intersection type
2+
self type cannot take part in an intersection type when unresolved
33
--FILE--
44
<?php
55

6-
class A {
6+
trait T {
77
public function foo(): self&Iterator {}
88
}
99

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
parent type cannot take part in an intersection type
3+
--FILE--
4+
<?php
5+
6+
class A {}
7+
8+
class B extends A {
9+
public function foo(): parent&Iterator {}
10+
}
11+
12+
class C extends A {
13+
public function foo(): self&Iterator {}
14+
}
15+
16+
?>
17+
==DONE==
18+
--EXPECT--
19+
==DONE==

Zend/tests/type_declarations/union_types/redundant_types/duplicate_relative_class_parent_type.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ class Bar extends Foo {
1212

1313
?>
1414
--EXPECTF--
15-
Fatal error: Duplicate type parent is redundant in %s on line %d
15+
Fatal error: Duplicate type Foo is redundant in %s on line %d

Zend/tests/type_declarations/union_types/redundant_types/duplicate_relative_class_self_type.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ class Foo {
99

1010
?>
1111
--EXPECTF--
12-
Fatal error: Duplicate type self is redundant in %s on line %d
12+
Fatal error: Duplicate type Foo is redundant in %s on line %d

Zend/tests/type_declarations/union_types/redundant_types/duplicate_resolved_relative_class_type_variation1.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ class Foo {
99

1010
?>
1111
--EXPECTF--
12-
Fatal error: self resolves to Foo which is redundant in %s on line %d
12+
Fatal error: Duplicate type Foo is redundant in %s on line %d

Zend/tests/type_declarations/union_types/redundant_types/duplicate_resolved_relative_class_type_variation2.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ class Foo {
99

1010
?>
1111
--EXPECTF--
12-
Fatal error: self resolves to Foo which is redundant in %s on line %d
12+
Fatal error: Duplicate type Foo is redundant in %s on line %d

Zend/tests/type_declarations/union_types/redundant_types/duplicate_resolved_relative_class_type_variation3.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ class Bar extends Foo {
1212

1313
?>
1414
--EXPECTF--
15-
Fatal error: parent resolves to Foo which is redundant in %s on line %d
15+
Fatal error: Duplicate type Foo is redundant in %s on line %d

Zend/tests/type_declarations/union_types/redundant_types/duplicate_resolved_relative_class_type_variation4.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ class Bar extends Foo {
1212

1313
?>
1414
--EXPECTF--
15-
Fatal error: parent resolves to Foo which is redundant in %s on line %d
15+
Fatal error: Duplicate type Foo is redundant in %s on line %d

Zend/zend_compile.c

Lines changed: 11 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1354,8 +1354,6 @@ static zend_string *add_intersection_type(zend_string *str,
13541354
ZEND_TYPE_LIST_FOREACH(intersection_type_list, single_type) {
13551355
ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*single_type));
13561356
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*single_type));
1357-
ZEND_ASSERT(!ZEND_TYPE_IS_RELATIVE_SELF(*single_type) && "Compile time disallowed to have 'self' in intersection");
1358-
ZEND_ASSERT(!ZEND_TYPE_IS_RELATIVE_PARENT(*single_type) && "Compile time disallowed to have 'parent' in intersection");
13591357

13601358
intersection_str = add_type_string(intersection_str, ZEND_TYPE_NAME(*single_type), /* is_intersection */ true);
13611359
} ZEND_TYPE_LIST_FOREACH_END();
@@ -1390,29 +1388,13 @@ zend_string *zend_type_to_string_resolved(zend_type type, zend_class_entry *scop
13901388
ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type));
13911389
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*list_type));
13921390

1393-
/* We already have resolved types from compile time
1394-
* Mimic unresolved types for BC with "self" and "parent" */
1395-
if (!scope && ZEND_TYPE_IS_RELATIVE_SELF(*list_type)) {
1396-
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_SELF), /* is_intersection */ false);
1397-
} else if (!scope && ZEND_TYPE_IS_RELATIVE_PARENT(*list_type)) {
1398-
str = add_type_string(str, ZSTR_KNOWN(ZEND_STR_PARENT), /* is_intersection */ false);
1399-
} else {
1400-
zend_string *name = ZEND_TYPE_NAME(*list_type);
1401-
zend_string *resolved = resolve_class_name(name, scope);
1402-
str = add_type_string(str, resolved, /* is_intersection */ false);
1403-
zend_string_release(resolved);
1404-
}
1391+
zend_string *name = ZEND_TYPE_NAME(*list_type);
1392+
zend_string *resolved = resolve_class_name(name, scope);
1393+
str = add_type_string(str, resolved, /* is_intersection */ false);
1394+
zend_string_release(resolved);
14051395
} ZEND_TYPE_LIST_FOREACH_END();
14061396
} else if (ZEND_TYPE_HAS_NAME(type)) {
1407-
/* We already have resolved types from compile time
1408-
* Mimic unresolved types for BC with "self" and "parent" */
1409-
if (!scope && ZEND_TYPE_IS_RELATIVE_SELF(type)) {
1410-
str = ZSTR_KNOWN(ZEND_STR_SELF);
1411-
} else if (!scope && ZEND_TYPE_IS_RELATIVE_PARENT(type)) {
1412-
str = ZSTR_KNOWN(ZEND_STR_PARENT);
1413-
} else {
1414-
str = resolve_class_name(ZEND_TYPE_NAME(type), scope);
1415-
}
1397+
str = resolve_class_name(ZEND_TYPE_NAME(type), scope);
14161398
}
14171399

14181400
uint32_t type_mask = ZEND_TYPE_PURE_MASK(type);
@@ -6659,7 +6641,6 @@ static zend_type zend_compile_single_typename(zend_ast *ast)
66596641
} else {
66606642
const char *correct_name;
66616643
uint32_t fetch_type = zend_get_class_fetch_type_ast(ast);
6662-
uint32_t type_flags = 0;
66636644
zend_string *class_name = type_name;
66646645

66656646
if (fetch_type == ZEND_FETCH_CLASS_DEFAULT) {
@@ -6670,15 +6651,13 @@ static zend_type zend_compile_single_typename(zend_ast *ast)
66706651

66716652
zend_ensure_valid_class_fetch_type(fetch_type);
66726653
if (fetch_type == ZEND_FETCH_CLASS_SELF) {
6673-
type_flags = _ZEND_TYPE_SELF_BIT;
66746654
/* Scope might be unknown for unbound closures and traits */
66756655
if (zend_is_scope_known()) {
66766656
class_name = CG(active_class_entry)->name;
66776657
ZEND_ASSERT(class_name && "must know class name when resolving self type at compile time");
66786658
}
66796659
} else {
66806660
ZEND_ASSERT(fetch_type == ZEND_FETCH_CLASS_PARENT);
6681-
type_flags = _ZEND_TYPE_PARENT_BIT;
66826661
/* Scope might be unknown for unbound closures and traits */
66836662
if (zend_is_scope_known()) {
66846663
class_name = CG(active_class_entry)->parent_name;
@@ -6709,7 +6688,7 @@ static zend_type zend_compile_single_typename(zend_ast *ast)
67096688

67106689
class_name = zend_new_interned_string(class_name);
67116690
zend_alloc_ce_cache(class_name);
6712-
return (zend_type) ZEND_TYPE_INIT_CLASS(class_name, /* allow null */ false, type_flags);
6691+
return (zend_type) ZEND_TYPE_INIT_CLASS(class_name, /* allow null */ false, 0);
67136692
}
67146693
}
67156694
}
@@ -6791,28 +6770,7 @@ static void zend_is_type_list_redundant_by_single_type(zend_type_list *type_list
67916770
}
67926771
if (zend_string_equals_ci(ZEND_TYPE_NAME(type_list->types[i]), ZEND_TYPE_NAME(type))) {
67936772
zend_string *single_type_str = zend_type_to_string(type);
6794-
if (ZEND_TYPE_IS_RELATIVE_TYPE(type)) {
6795-
if ( (
6796-
ZEND_TYPE_FULL_MASK(type)
6797-
& ZEND_TYPE_FULL_MASK(type_list->types[i])
6798-
& (_ZEND_TYPE_RELATIVE_TYPE_MASK)) != 0
6799-
) {
6800-
zend_error_noreturn(E_COMPILE_ERROR, "Duplicate type %s is redundant", ZSTR_VAL(single_type_str));
6801-
}
6802-
/* zend_type_to_string() will return "self" or "parent" where the resolved type is stored in
6803-
* ZEND_TYPE_NAME() */
6804-
zend_error_noreturn(E_COMPILE_ERROR, "%s resolves to %s which is redundant",
6805-
ZSTR_VAL(single_type_str), ZSTR_VAL(ZEND_TYPE_NAME(type))
6806-
);
6807-
} else if (ZEND_TYPE_IS_RELATIVE_TYPE(type_list->types[i])) {
6808-
/* zend_type_to_string() will return "self" or "parent" where the resolved type is stored in
6809-
* ZEND_TYPE_NAME() */
6810-
zend_error_noreturn(E_COMPILE_ERROR, "%s resolves to %s which is redundant",
6811-
ZEND_TYPE_IS_RELATIVE_SELF(type_list->types[i]) ? "self" : "parent", ZSTR_VAL(ZEND_TYPE_NAME(type))
6812-
);
6813-
} else {
6814-
zend_error_noreturn(E_COMPILE_ERROR, "Duplicate type %s is redundant", ZSTR_VAL(single_type_str));
6815-
}
6773+
zend_error_noreturn(E_COMPILE_ERROR, "Duplicate type %s is redundant", ZSTR_VAL(single_type_str));
68166774
}
68176775
}
68186776
}
@@ -6908,8 +6866,6 @@ static zend_type zend_compile_typename_ex(
69086866
/* The first class type can be stored directly as the type ptr payload. */
69096867
ZEND_TYPE_SET_PTR(type, ZEND_TYPE_NAME(single_type));
69106868
ZEND_TYPE_FULL_MASK(type) |= _ZEND_TYPE_NAME_BIT;
6911-
/* Add flags indicating the named type is self/parent */
6912-
ZEND_TYPE_FULL_MASK(type) |= (ZEND_TYPE_FULL_MASK(single_type) & _ZEND_TYPE_RELATIVE_TYPE_MASK);
69136869
} else {
69146870
if (type_list->num_types == 0) {
69156871
/* Switch from single name to name list. */
@@ -6918,8 +6874,6 @@ static zend_type zend_compile_typename_ex(
69186874
/* Clear MAY_BE_* type flags */
69196875
ZEND_TYPE_FULL_MASK(type_list->types[0]) &= ~_ZEND_TYPE_MAY_BE_MASK;
69206876
ZEND_TYPE_SET_LIST(type, type_list);
6921-
/* Clear flags indicating the named type is self/parent */
6922-
ZEND_TYPE_FULL_MASK(type) &= ~_ZEND_TYPE_RELATIVE_TYPE_MASK;
69236877
}
69246878

69256879
type_list->types[type_list->num_types++] = single_type;
@@ -6981,11 +6935,10 @@ static zend_type zend_compile_typename_ex(
69816935
zend_string_release_ex(standard_type_str, false);
69826936
}
69836937
/* Check for "self" and "parent" too */
6984-
if (ZEND_TYPE_IS_RELATIVE_SELF(single_type)) {
6985-
zend_error_noreturn(E_COMPILE_ERROR, "Type self cannot be part of an intersection type");
6986-
}
6987-
if (ZEND_TYPE_IS_RELATIVE_PARENT(single_type)) {
6988-
zend_error_noreturn(E_COMPILE_ERROR, "Type parent cannot be part of an intersection type");
6938+
if (zend_string_equals_literal_ci(ZEND_TYPE_NAME(single_type), "self")
6939+
|| zend_string_equals_literal_ci(ZEND_TYPE_NAME(single_type), "parent")) {
6940+
zend_error_noreturn(E_COMPILE_ERROR,
6941+
"Type %s cannot be part of an intersection type", ZSTR_VAL(ZEND_TYPE_NAME(single_type)));
69896942
}
69906943

69916944
/* Add type to the type list */

Zend/zend_inheritance.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1955,10 +1955,10 @@ static inline bool zend_was_type_resolved(zend_type original_type, zend_type res
19551955
static zend_type zend_resolve_name_type(zend_type type, const zend_class_entry *const ce)
19561956
{
19571957
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(type));
1958-
if (ZEND_TYPE_IS_RELATIVE_SELF(type)) {
1958+
if (zend_string_equals_literal_ci(ZEND_TYPE_NAME(type), "self")) {
19591959
zend_type resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(zend_string_copy(ce->name), /* allows_null */ false, /* extra_flags */ ZEND_TYPE_FULL_MASK(type));
19601960
return resolved_type;
1961-
} else if (ZEND_TYPE_IS_RELATIVE_PARENT(type)) {
1961+
} else if (zend_string_equals_literal_ci(ZEND_TYPE_NAME(type), "parent")) {
19621962
if (!ce->parent) {
19631963
zend_error_noreturn(E_COMPILE_ERROR,
19641964
"Cannot use trait which has \"parent\" as a type when current class scope has no parent");

Zend/zend_types.h

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -142,12 +142,8 @@ typedef struct {
142142
zend_type types[1];
143143
} zend_type_list;
144144

145-
#define _ZEND_TYPE_EXTRA_FLAGS_SHIFT 27
146-
#define _ZEND_TYPE_MASK ((1u << 27) - 1)
147-
/* Only one of these bits may be set. */
148-
#define _ZEND_TYPE_PARENT_BIT (1u << 26)
149-
#define _ZEND_TYPE_SELF_BIT (1u << 25)
150-
#define _ZEND_TYPE_RELATIVE_TYPE_MASK (_ZEND_TYPE_SELF_BIT|_ZEND_TYPE_PARENT_BIT)
145+
#define _ZEND_TYPE_EXTRA_FLAGS_SHIFT 25
146+
#define _ZEND_TYPE_MASK ((1u << 25) - 1)
151147
/* Only one of these bits may be set. */
152148
#define _ZEND_TYPE_NAME_BIT (1u << 24)
153149
// Used to signify that type.ptr is not a `zend_string*` but a `const char*`,
@@ -170,17 +166,6 @@ typedef struct {
170166
#define ZEND_TYPE_IS_SET(t) \
171167
(((t).type_mask & _ZEND_TYPE_MASK) != 0)
172168

173-
174-
/* To determine if the type resolved type was written with "self" or "parent" */
175-
#define ZEND_TYPE_IS_RELATIVE_TYPE(t) \
176-
((((t).type_mask) & _ZEND_TYPE_RELATIVE_TYPE_MASK) != 0)
177-
/* To determine if the type resolved type was written with "self" */
178-
#define ZEND_TYPE_IS_RELATIVE_SELF(t) \
179-
((((t).type_mask) & _ZEND_TYPE_SELF_BIT) != 0)
180-
/* To determine if the type resolved type was written with "parent" */
181-
#define ZEND_TYPE_IS_RELATIVE_PARENT(t) \
182-
((((t).type_mask) & _ZEND_TYPE_PARENT_BIT) != 0)
183-
184169
/* If a type is complex it means it's either a list with a union or intersection,
185170
* or the void pointer is a class name */
186171
#define ZEND_TYPE_IS_COMPLEX(t) \

ext/reflection/php_reflection.c

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1397,7 +1397,10 @@ static reflection_type_kind get_type_kind(zend_type type) {
13971397
}
13981398

13991399
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(type));
1400-
if (ZEND_TYPE_IS_RELATIVE_TYPE(type)) {
1400+
if (
1401+
zend_string_equals_literal_ci(ZEND_TYPE_NAME(type), "self")
1402+
|| zend_string_equals_literal_ci(ZEND_TYPE_NAME(type), "parent")
1403+
) {
14011404
return RELATIVE_TYPE;
14021405
}
14031406
return NAMED_TYPE;
@@ -2717,14 +2720,15 @@ ZEND_METHOD(ReflectionParameter, getClass)
27172720
* TODO: Think about moving these checks to the compiler or some sort of
27182721
* lint-mode.
27192722
*/
2720-
if (ZEND_TYPE_IS_RELATIVE_SELF(param->arg_info->type)) {
2723+
zend_string *class_name = ZEND_TYPE_NAME(param->arg_info->type);
2724+
if (zend_string_equals_literal_ci(class_name, "self")) {
27212725
ce = param->fptr->common.scope;
27222726
if (!ce) {
27232727
zend_throw_exception_ex(reflection_exception_ptr, 0,
27242728
"Parameter uses \"self\" as type but function is not a class member");
27252729
RETURN_THROWS();
27262730
}
2727-
} else if (ZEND_TYPE_IS_RELATIVE_PARENT(param->arg_info->type)) {
2731+
} else if (zend_string_equals_literal_ci(class_name, "parent")) {
27282732
ce = param->fptr->common.scope;
27292733
if (!ce) {
27302734
zend_throw_exception_ex(reflection_exception_ptr, 0,
@@ -2738,7 +2742,6 @@ ZEND_METHOD(ReflectionParameter, getClass)
27382742
}
27392743
ce = ce->parent;
27402744
} else {
2741-
zend_string *class_name = ZEND_TYPE_NAME(param->arg_info->type);
27422745
ce = zend_lookup_class(class_name);
27432746
if (!ce) {
27442747
zend_throw_exception_ex(reflection_exception_ptr, 0,
@@ -3186,11 +3189,11 @@ ZEND_METHOD(ReflectionRelativeClassType, resolveToNamedType)
31863189
"Cannot resolve \"static\" type of an interface");
31873190
RETURN_THROWS();
31883191
}
3189-
resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(intern->ce->name, allows_null, /*extra flags */ 0);
3192+
resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(intern->ce->name, allows_null, /* extra flags */ 0);
31903193
} else {
3191-
ZEND_ASSERT(ZEND_TYPE_IS_RELATIVE_TYPE(param->type));
3194+
ZEND_ASSERT(zend_string_equals_literal_ci(ZEND_TYPE_NAME(param->type), "self") || zend_string_equals_literal_ci(ZEND_TYPE_NAME(param->type), "parent"));
31923195
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(param->type));
3193-
resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(ZEND_TYPE_NAME(param->type), allows_null, /*extra flags */ 0);
3196+
resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(ZEND_TYPE_NAME(param->type), allows_null, /* extra flags */ 0);
31943197
}
31953198

31963199
reflection_type_factory(resolved_type, return_value, /* legacy_behavior */ true, intern->ce);
@@ -3232,14 +3235,7 @@ ZEND_METHOD(ReflectionUnionType, getTypes)
32323235
} ZEND_TYPE_LIST_FOREACH_END();
32333236
} else if (ZEND_TYPE_HAS_NAME(param->type)) {
32343237
zend_string *name = ZEND_TYPE_NAME(param->type);
3235-
uint32_t type_flags = 0;
3236-
if (ZEND_TYPE_IS_RELATIVE_SELF(param->type)) {
3237-
type_flags = _ZEND_TYPE_SELF_BIT;
3238-
}
3239-
if (ZEND_TYPE_IS_RELATIVE_PARENT(param->type)) {
3240-
type_flags = _ZEND_TYPE_PARENT_BIT;
3241-
}
3242-
append_type(return_value, (zend_type) ZEND_TYPE_INIT_CLASS(name, /* allow_null */ false, /* extra flags */ type_flags), /* object_ce */ intern->ce);
3238+
append_type(return_value, (zend_type) ZEND_TYPE_INIT_CLASS(name, /* allow_null */ false, /* extra flags */ 0), /* object_ce */ intern->ce);
32433239
}
32443240

32453241
type_mask = ZEND_TYPE_PURE_MASK(param->type);

ext/reflection/tests/bug80190.phpt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,14 @@ foreach ((new ReflectionClass(C::class))->getMethods() as $method) {
4747
?>
4848
--EXPECT--
4949
C::a()
50-
$method->getReturnType() returns ReflectionRelativeClassType
51-
$method->getReturnType()->__toString() returns self
50+
$method->getReturnType() returns ReflectionNamedType
51+
$method->getReturnType()->__toString() returns C
5252

5353
C::b()
5454
$method->getReturnType() returns ReflectionUnionType
55-
$method->getReturnType()->__toString() returns stdClass|self
55+
$method->getReturnType()->__toString() returns stdClass|C
5656
$method->getReturnType()->getTypes() returns an array with 2 element(s)
57-
type(s) in union: ReflectionNamedType(stdClass), ReflectionRelativeClassType(self)
57+
type(s) in union: ReflectionNamedType(stdClass), ReflectionNamedType(C)
5858

5959
C::c()
6060
$method->getReturnType() returns ReflectionRelativeClassType

ext/reflection/tests/types/ReflectionType_001.phpt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,12 @@ string(10) "SplSubject"
166166
bool(true)
167167
bool(false)
168168
bool(false)
169-
string(4) "self"
169+
string(1) "c"
170170
** Method 2 - parameter 0
171171
bool(true)
172172
bool(false)
173173
bool(false)
174-
string(6) "parent"
174+
string(8) "stdClass"
175175
** Method 3 - parameter 0
176176
bool(true)
177177
bool(false)
@@ -195,12 +195,12 @@ string(3) "int"
195195
bool(true)
196196
bool(false)
197197
bool(false)
198-
string(4) "self"
198+
string(1) "c"
199199
** Function/method return type 4
200200
bool(true)
201201
bool(false)
202202
bool(false)
203-
string(6) "parent"
203+
string(8) "stdClass"
204204
** Function/method return type 5
205205
bool(true)
206206
bool(false)

0 commit comments

Comments
 (0)