Skip to content

Commit 1e30a92

Browse files
committed
Do not preserve BC for self/parent and always resolve when possible
1 parent fcf2530 commit 1e30a92

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);
@@ -6638,7 +6620,6 @@ static zend_type zend_compile_single_typename(zend_ast *ast)
66386620
} else {
66396621
const char *correct_name;
66406622
uint32_t fetch_type = zend_get_class_fetch_type_ast(ast);
6641-
uint32_t type_flags = 0;
66426623
zend_string *class_name = type_name;
66436624

66446625
if (fetch_type == ZEND_FETCH_CLASS_DEFAULT) {
@@ -6649,15 +6630,13 @@ static zend_type zend_compile_single_typename(zend_ast *ast)
66496630

66506631
zend_ensure_valid_class_fetch_type(fetch_type);
66516632
if (fetch_type == ZEND_FETCH_CLASS_SELF) {
6652-
type_flags = _ZEND_TYPE_SELF_BIT;
66536633
/* Scope might be unknown for unbound closures and traits */
66546634
if (zend_is_scope_known()) {
66556635
class_name = CG(active_class_entry)->name;
66566636
ZEND_ASSERT(class_name && "must know class name when resolving self type at compile time");
66576637
}
66586638
} else {
66596639
ZEND_ASSERT(fetch_type == ZEND_FETCH_CLASS_PARENT);
6660-
type_flags = _ZEND_TYPE_PARENT_BIT;
66616640
/* Scope might be unknown for unbound closures and traits */
66626641
if (zend_is_scope_known()) {
66636642
class_name = CG(active_class_entry)->parent_name;
@@ -6688,7 +6667,7 @@ static zend_type zend_compile_single_typename(zend_ast *ast)
66886667

66896668
class_name = zend_new_interned_string(class_name);
66906669
zend_alloc_ce_cache(class_name);
6691-
return (zend_type) ZEND_TYPE_INIT_CLASS(class_name, /* allow null */ false, type_flags);
6670+
return (zend_type) ZEND_TYPE_INIT_CLASS(class_name, /* allow null */ false, 0);
66926671
}
66936672
}
66946673
}
@@ -6770,28 +6749,7 @@ static void zend_is_type_list_redundant_by_single_type(zend_type_list *type_list
67706749
}
67716750
if (zend_string_equals_ci(ZEND_TYPE_NAME(type_list->types[i]), ZEND_TYPE_NAME(type))) {
67726751
zend_string *single_type_str = zend_type_to_string(type);
6773-
if (ZEND_TYPE_IS_RELATIVE_TYPE(type)) {
6774-
if ( (
6775-
ZEND_TYPE_FULL_MASK(type)
6776-
& ZEND_TYPE_FULL_MASK(type_list->types[i])
6777-
& (_ZEND_TYPE_RELATIVE_TYPE_MASK)) != 0
6778-
) {
6779-
zend_error_noreturn(E_COMPILE_ERROR, "Duplicate type %s is redundant", ZSTR_VAL(single_type_str));
6780-
}
6781-
/* zend_type_to_string() will return "self" or "parent" where the resolved type is stored in
6782-
* ZEND_TYPE_NAME() */
6783-
zend_error_noreturn(E_COMPILE_ERROR, "%s resolves to %s which is redundant",
6784-
ZSTR_VAL(single_type_str), ZSTR_VAL(ZEND_TYPE_NAME(type))
6785-
);
6786-
} else if (ZEND_TYPE_IS_RELATIVE_TYPE(type_list->types[i])) {
6787-
/* zend_type_to_string() will return "self" or "parent" where the resolved type is stored in
6788-
* ZEND_TYPE_NAME() */
6789-
zend_error_noreturn(E_COMPILE_ERROR, "%s resolves to %s which is redundant",
6790-
ZEND_TYPE_IS_RELATIVE_SELF(type_list->types[i]) ? "self" : "parent", ZSTR_VAL(ZEND_TYPE_NAME(type))
6791-
);
6792-
} else {
6793-
zend_error_noreturn(E_COMPILE_ERROR, "Duplicate type %s is redundant", ZSTR_VAL(single_type_str));
6794-
}
6752+
zend_error_noreturn(E_COMPILE_ERROR, "Duplicate type %s is redundant", ZSTR_VAL(single_type_str));
67956753
}
67966754
}
67976755
}
@@ -6887,8 +6845,6 @@ static zend_type zend_compile_typename_ex(
68876845
/* The first class type can be stored directly as the type ptr payload. */
68886846
ZEND_TYPE_SET_PTR(type, ZEND_TYPE_NAME(single_type));
68896847
ZEND_TYPE_FULL_MASK(type) |= _ZEND_TYPE_NAME_BIT;
6890-
/* Add flags indicating the named type is self/parent */
6891-
ZEND_TYPE_FULL_MASK(type) |= (ZEND_TYPE_FULL_MASK(single_type) & _ZEND_TYPE_RELATIVE_TYPE_MASK);
68926848
} else {
68936849
if (type_list->num_types == 0) {
68946850
/* Switch from single name to name list. */
@@ -6897,8 +6853,6 @@ static zend_type zend_compile_typename_ex(
68976853
/* Clear MAY_BE_* type flags */
68986854
ZEND_TYPE_FULL_MASK(type_list->types[0]) &= ~_ZEND_TYPE_MAY_BE_MASK;
68996855
ZEND_TYPE_SET_LIST(type, type_list);
6900-
/* Clear flags indicating the named type is self/parent */
6901-
ZEND_TYPE_FULL_MASK(type) &= ~_ZEND_TYPE_RELATIVE_TYPE_MASK;
69026856
}
69036857

69046858
type_list->types[type_list->num_types++] = single_type;
@@ -6960,11 +6914,10 @@ static zend_type zend_compile_typename_ex(
69606914
zend_string_release_ex(standard_type_str, false);
69616915
}
69626916
/* Check for "self" and "parent" too */
6963-
if (ZEND_TYPE_IS_RELATIVE_SELF(single_type)) {
6964-
zend_error_noreturn(E_COMPILE_ERROR, "Type self cannot be part of an intersection type");
6965-
}
6966-
if (ZEND_TYPE_IS_RELATIVE_PARENT(single_type)) {
6967-
zend_error_noreturn(E_COMPILE_ERROR, "Type parent cannot be part of an intersection type");
6917+
if (zend_string_equals_literal_ci(ZEND_TYPE_NAME(single_type), "self")
6918+
|| zend_string_equals_literal_ci(ZEND_TYPE_NAME(single_type), "parent")) {
6919+
zend_error_noreturn(E_COMPILE_ERROR,
6920+
"Type %s cannot be part of an intersection type", ZSTR_VAL(ZEND_TYPE_NAME(single_type)));
69686921
}
69696922

69706923
/* 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
@@ -1368,7 +1368,10 @@ static reflection_type_kind get_type_kind(zend_type type) {
13681368
}
13691369

13701370
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(type));
1371-
if (ZEND_TYPE_IS_RELATIVE_TYPE(type)) {
1371+
if (
1372+
zend_string_equals_literal_ci(ZEND_TYPE_NAME(type), "self")
1373+
|| zend_string_equals_literal_ci(ZEND_TYPE_NAME(type), "parent")
1374+
) {
13721375
return RELATIVE_TYPE;
13731376
}
13741377
return NAMED_TYPE;
@@ -2688,14 +2691,15 @@ ZEND_METHOD(ReflectionParameter, getClass)
26882691
* TODO: Think about moving these checks to the compiler or some sort of
26892692
* lint-mode.
26902693
*/
2691-
if (ZEND_TYPE_IS_RELATIVE_SELF(param->arg_info->type)) {
2694+
zend_string *class_name = ZEND_TYPE_NAME(param->arg_info->type);
2695+
if (zend_string_equals_literal_ci(class_name, "self")) {
26922696
ce = param->fptr->common.scope;
26932697
if (!ce) {
26942698
zend_throw_exception_ex(reflection_exception_ptr, 0,
26952699
"Parameter uses \"self\" as type but function is not a class member");
26962700
RETURN_THROWS();
26972701
}
2698-
} else if (ZEND_TYPE_IS_RELATIVE_PARENT(param->arg_info->type)) {
2702+
} else if (zend_string_equals_literal_ci(class_name, "parent")) {
26992703
ce = param->fptr->common.scope;
27002704
if (!ce) {
27012705
zend_throw_exception_ex(reflection_exception_ptr, 0,
@@ -2709,7 +2713,6 @@ ZEND_METHOD(ReflectionParameter, getClass)
27092713
}
27102714
ce = ce->parent;
27112715
} else {
2712-
zend_string *class_name = ZEND_TYPE_NAME(param->arg_info->type);
27132716
ce = zend_lookup_class(class_name);
27142717
if (!ce) {
27152718
zend_throw_exception_ex(reflection_exception_ptr, 0,
@@ -3157,11 +3160,11 @@ ZEND_METHOD(ReflectionRelativeClassType, resolveToNamedType)
31573160
"Cannot resolve \"static\" type of an interface");
31583161
RETURN_THROWS();
31593162
}
3160-
resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(intern->ce->name, allows_null, /*extra flags */ 0);
3163+
resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(intern->ce->name, allows_null, /* extra flags */ 0);
31613164
} else {
3162-
ZEND_ASSERT(ZEND_TYPE_IS_RELATIVE_TYPE(param->type));
3165+
ZEND_ASSERT(zend_string_equals_literal_ci(ZEND_TYPE_NAME(param->type), "self") || zend_string_equals_literal_ci(ZEND_TYPE_NAME(param->type), "parent"));
31633166
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(param->type));
3164-
resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(ZEND_TYPE_NAME(param->type), allows_null, /*extra flags */ 0);
3167+
resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(ZEND_TYPE_NAME(param->type), allows_null, /* extra flags */ 0);
31653168
}
31663169

31673170
reflection_type_factory(resolved_type, return_value, /* legacy_behavior */ true, intern->ce);
@@ -3203,14 +3206,7 @@ ZEND_METHOD(ReflectionUnionType, getTypes)
32033206
} ZEND_TYPE_LIST_FOREACH_END();
32043207
} else if (ZEND_TYPE_HAS_NAME(param->type)) {
32053208
zend_string *name = ZEND_TYPE_NAME(param->type);
3206-
uint32_t type_flags = 0;
3207-
if (ZEND_TYPE_IS_RELATIVE_SELF(param->type)) {
3208-
type_flags = _ZEND_TYPE_SELF_BIT;
3209-
}
3210-
if (ZEND_TYPE_IS_RELATIVE_PARENT(param->type)) {
3211-
type_flags = _ZEND_TYPE_PARENT_BIT;
3212-
}
3213-
append_type(return_value, (zend_type) ZEND_TYPE_INIT_CLASS(name, /* allow_null */ false, /* extra flags */ type_flags), /* object_ce */ intern->ce);
3209+
append_type(return_value, (zend_type) ZEND_TYPE_INIT_CLASS(name, /* allow_null */ false, /* extra flags */ 0), /* object_ce */ intern->ce);
32143210
}
32153211

32163212
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)