diff options
30 files changed, 506 insertions, 3 deletions
@@ -236,6 +236,26 @@ PHP 8.0 UPGRADE NOTES "Illegal string offset 'string'" for illegal string offsets. The behavior of explicit casts to int/float from strings has not been changed. RFC: https://wiki.php.net/rfc/saner-numeric-strings + . Magic Methods will now have their arguments and return types + checked if they have them declared. The signatures should + match the following list: + + __call(string $name, array $arguments): mixed + __callStatic(string $name, array $arguments): mixed + __clone(): void + __debugInfo(): ?array + __get(string $name): mixed + __invoke(mixed $arguments): mixed + __isset(string $name): bool + __serialize(): array + __set(string $name, mixed $value): void + __set_state(array $properties): object + __sleep(): array + __unserialize(array $data): void + __unset(string $name): void + __wakeup(): void + + RFC: https://wiki.php.net/rfc/magic-methods-signature - COM: . Removed the ability to import case-insensitive constants from type diff --git a/Zend/tests/magic_methods_011.phpt b/Zend/tests/magic_methods_011.phpt new file mode 100644 index 0000000000..5ce536ae40 --- /dev/null +++ b/Zend/tests/magic_methods_011.phpt @@ -0,0 +1,10 @@ +--TEST-- +__set first parameter should be a string when typed +--FILE-- +<?php +class Foo { + function __set(\Countable $name, $value) {} +} +?> +--EXPECTF-- +Fatal error: Foo::__set(): Parameter #1 ($name) must be of type string when declared in %s on line %d diff --git a/Zend/tests/magic_methods_012.phpt b/Zend/tests/magic_methods_012.phpt new file mode 100644 index 0000000000..4ac3952c4d --- /dev/null +++ b/Zend/tests/magic_methods_012.phpt @@ -0,0 +1,10 @@ +--TEST-- +__get first parameter should be a string when typed +--FILE-- +<?php +class Foo { + function __get(int $name) {} +} +?> +--EXPECTF-- +Fatal error: Foo::__get(): Parameter #1 ($name) must be of type string when declared in %s on line %d diff --git a/Zend/tests/magic_methods_013.phpt b/Zend/tests/magic_methods_013.phpt new file mode 100644 index 0000000000..03a4fb7ea7 --- /dev/null +++ b/Zend/tests/magic_methods_013.phpt @@ -0,0 +1,10 @@ +--TEST-- +__isset first parameter should be a string when typed +--FILE-- +<?php +class Foo { + function __isset(\stdClass $name) {} +} +?> +--EXPECTF-- +Fatal error: Foo::__isset(): Parameter #1 ($name) must be of type string when declared in %s on line %d diff --git a/Zend/tests/magic_methods_014.phpt b/Zend/tests/magic_methods_014.phpt new file mode 100644 index 0000000000..783b6003dc --- /dev/null +++ b/Zend/tests/magic_methods_014.phpt @@ -0,0 +1,10 @@ +--TEST-- +__unset first parameter should be a string when typed +--FILE-- +<?php +class Foo { + function __unset(array $name) {} +} +?> +--EXPECTF-- +Fatal error: Foo::__unset(): Parameter #1 ($name) must be of type string when declared in %s on line %d diff --git a/Zend/tests/magic_methods_015.phpt b/Zend/tests/magic_methods_015.phpt new file mode 100644 index 0000000000..d5e93c9ef0 --- /dev/null +++ b/Zend/tests/magic_methods_015.phpt @@ -0,0 +1,10 @@ +--TEST-- +__call first parameter should be a string typed +--FILE-- +<?php +class Foo { + function __call(int $name, array $arguments) {} +} +?> +--EXPECTF-- +Fatal error: Foo::__call(): Parameter #1 ($name) must be of type string when declared in %s on line %d diff --git a/Zend/tests/magic_methods_016.phpt b/Zend/tests/magic_methods_016.phpt new file mode 100644 index 0000000000..a0ac45e42a --- /dev/null +++ b/Zend/tests/magic_methods_016.phpt @@ -0,0 +1,10 @@ +--TEST-- +__call second parameter should be an array when typed +--FILE-- +<?php +class Foo { + function __call(string $name, \Arguments $arguments) {} +} +?> +--EXPECTF-- +Fatal error: Foo::__call(): Parameter #2 ($arguments) must be of type array when declared in %s on line %d diff --git a/Zend/tests/magic_methods_017.phpt b/Zend/tests/magic_methods_017.phpt new file mode 100644 index 0000000000..9afb089f31 --- /dev/null +++ b/Zend/tests/magic_methods_017.phpt @@ -0,0 +1,10 @@ +--TEST-- +__callStatic first parameter should be a string typed +--FILE-- +<?php +class Foo { + static function __callStatic(int $name, array $arguments) {} +} +?> +--EXPECTF-- +Fatal error: Foo::__callStatic(): Parameter #1 ($name) must be of type string when declared in %s on line %d diff --git a/Zend/tests/magic_methods_018.phpt b/Zend/tests/magic_methods_018.phpt new file mode 100644 index 0000000000..faddd3cca1 --- /dev/null +++ b/Zend/tests/magic_methods_018.phpt @@ -0,0 +1,10 @@ +--TEST-- +__callStatic second parameter should be an array typed +--FILE-- +<?php +class Foo { + static function __callStatic(string $name, \Arguments $args) {} +} +?> +--EXPECTF-- +Fatal error: Foo::__callStatic(): Parameter #2 ($args) must be of type array when declared in %s on line %d diff --git a/Zend/tests/magic_methods_019.phpt b/Zend/tests/magic_methods_019.phpt new file mode 100644 index 0000000000..85823e6c40 --- /dev/null +++ b/Zend/tests/magic_methods_019.phpt @@ -0,0 +1,10 @@ +--TEST-- +__unserialize first parameter must be an array +--FILE-- +<?php +class Foo { + public function __unserialize(string $name) {} +} +?> +--EXPECTF-- +Fatal error: Foo::__unserialize(): Parameter #1 ($name) must be of type array when declared in %s on line %d diff --git a/Zend/tests/magic_methods_inheritance_rules.phpt b/Zend/tests/magic_methods_inheritance_rules.phpt new file mode 100644 index 0000000000..e91fdc7848 --- /dev/null +++ b/Zend/tests/magic_methods_inheritance_rules.phpt @@ -0,0 +1,70 @@ +--TEST-- +Magic Methods inheritance rules +--FILE-- +<?php +class ValidMagicMethods { + public function __call(string $name, array $arguments): mixed {} + + public static function __callStatic(string $name, array $arguments): mixed {} + + public function __clone(): void {} + + public function __debugInfo(): ?array {} + + public function __get(string $name): mixed {} + + public function __invoke(mixed $arguments): mixed {} + + public function __isset(string $name): bool {} + + public function __serialize(): array {} + + public function __set(string $name, mixed $value): void {} + + public static function __set_state(array $properties): object {} + + public function __sleep(): array {} + + public function __toString(): string {} + + public function __unserialize(array $data): void {} + + public function __unset(string $name): void {} + + public function __wakeup(): void {} +} + +class NarrowedReturnType extends ValidMagicMethods { + public function __call(string $name, array $arguments): string|float|null {} + + public static function __callStatic(string $name, array $arguments): ?array {} + + public function __debugInfo(): array {} + + public function __get(string $name): int|string {} + + public function __invoke(mixed $arguments): object {} +} + +class WidenedArgumentType extends NarrowedReturnType { + public function __call(string|array $name, array|string $arguments): string|float|null {} + + public static function __callStatic(string|object $name, array|object $arguments): ?array {} + + public function __get(string|array $name): int|string {} + + public function __isset(string|bool $name): bool {} + + public function __set(string|bool|float $name, mixed $value): void {} + + public static function __set_state(string|array $properties): object {} + + public function __unserialize(array|string $data): void {} + + public function __unset(string|array $name): void {} +} + +echo 'No problems!'; +?> +--EXPECT-- +No problems! diff --git a/Zend/tests/magic_methods_inheritance_rules_non_trivial_01.phpt b/Zend/tests/magic_methods_inheritance_rules_non_trivial_01.phpt new file mode 100644 index 0000000000..a57c8b7dc8 --- /dev/null +++ b/Zend/tests/magic_methods_inheritance_rules_non_trivial_01.phpt @@ -0,0 +1,18 @@ +--TEST-- +Magic Methods inheritance rules on a non-trivial class hierarchy +--FILE-- +<?php +class A { + public function __get(string|array $name): mixed {} // valid +} + +class B extends A { + public function __get(string|array|object $name): int {} // also valid +} + +class C extends B { + public function __get(string|array $name): int {} // this is invalid +} +?> +--EXPECTF-- +Fatal error: Declaration of C::__get(array|string $name): int must be compatible with B::__get(object|array|string $name): int in %s on line %d diff --git a/Zend/tests/magic_methods_inheritance_rules_non_trivial_02.phpt b/Zend/tests/magic_methods_inheritance_rules_non_trivial_02.phpt new file mode 100644 index 0000000000..72c20a7885 --- /dev/null +++ b/Zend/tests/magic_methods_inheritance_rules_non_trivial_02.phpt @@ -0,0 +1,18 @@ +--TEST-- +Magic Methods inheritance rules on a non-trivial class hierarchy +--FILE-- +<?php +class A { + public function __get(string|array $name): mixed {} // valid +} + +class B extends A { + public function __get(string|array|object $name): int {} // also valid +} + +class C extends B { + public function __get(string|array|object $name): int|float {} // this is invalid +} +?> +--EXPECTF-- +Fatal error: Declaration of C::__get(object|array|string $name): int|float must be compatible with B::__get(object|array|string $name): int in %s on line %d diff --git a/Zend/tests/magic_methods_sleep.phpt b/Zend/tests/magic_methods_sleep.phpt new file mode 100644 index 0000000000..593d8fc037 --- /dev/null +++ b/Zend/tests/magic_methods_sleep.phpt @@ -0,0 +1,10 @@ +--TEST-- +__sleep cannot take arguments +--FILE-- +<?php +class Foo { + public function __sleep(string $name) {} +} +?> +--EXPECTF-- +Fatal error: Method Foo::__sleep() cannot take arguments in %s on line %d diff --git a/Zend/tests/magic_methods_wakeup.phpt b/Zend/tests/magic_methods_wakeup.phpt new file mode 100644 index 0000000000..f4edb33576 --- /dev/null +++ b/Zend/tests/magic_methods_wakeup.phpt @@ -0,0 +1,10 @@ +--TEST-- +__wakeup cannot take arguments +--FILE-- +<?php +class Foo { + public function __wakeup(string $name) {} +} +?> +--EXPECTF-- +Fatal error: Method Foo::__wakeup() cannot take arguments in %s on line %d diff --git a/Zend/tests/return_types/019.phpt b/Zend/tests/return_types/019.phpt index 4be32b2474..652548c3f9 100644 --- a/Zend/tests/return_types/019.phpt +++ b/Zend/tests/return_types/019.phpt @@ -1,10 +1,11 @@ --TEST-- -__clone cannot declare a return type +__clone can only declare void return --FILE-- <?php class Foo { function __clone() : Foo {} } +?> --EXPECTF-- -Fatal error: %s::%s() cannot declare a return type in %s on line %d +Fatal error: Foo::__clone(): Return type must be void when declared in %s on line %d diff --git a/Zend/tests/return_types/033.phpt b/Zend/tests/return_types/033.phpt new file mode 100644 index 0000000000..e725465253 --- /dev/null +++ b/Zend/tests/return_types/033.phpt @@ -0,0 +1,10 @@ +--TEST-- +__set can only declare void return +--FILE-- +<?php +class Foo { + function __set($name, $value) : string {} +} +?> +--EXPECTF-- +Fatal error: Foo::__set(): Return type must be void when declared in %s on line %d diff --git a/Zend/tests/return_types/034.phpt b/Zend/tests/return_types/034.phpt new file mode 100644 index 0000000000..50324208cb --- /dev/null +++ b/Zend/tests/return_types/034.phpt @@ -0,0 +1,10 @@ +--TEST-- +__isset can only declare a boolean return type +--FILE-- +<?php +class Foo { + function __isset($name) : \stdClass|bool {} +} +?> +--EXPECTF-- +Fatal error: Foo::__isset(): Return type must be bool when declared in %s on line %d diff --git a/Zend/tests/return_types/035.phpt b/Zend/tests/return_types/035.phpt new file mode 100644 index 0000000000..fa2d331f55 --- /dev/null +++ b/Zend/tests/return_types/035.phpt @@ -0,0 +1,10 @@ +--TEST-- +__unset can only declare void return +--FILE-- +<?php +class Foo { + function __unset($name) : bool {} +} +?> +--EXPECTF-- +Fatal error: Foo::__unset(): Return type must be void when declared in %s on line %d diff --git a/Zend/tests/return_types/036.phpt b/Zend/tests/return_types/036.phpt new file mode 100644 index 0000000000..2f0847f21b --- /dev/null +++ b/Zend/tests/return_types/036.phpt @@ -0,0 +1,11 @@ +--TEST-- +__toString can only declare string return type +--FILE-- +<?php +class Foo { + public function __toString(): bool { + } +} +?> +--EXPECTF-- +Fatal error: Declaration of Foo::__toString(): bool must be compatible with Stringable::__toString(): string in %s on line %d diff --git a/Zend/tests/return_types/037.phpt b/Zend/tests/return_types/037.phpt new file mode 100644 index 0000000000..34569e494e --- /dev/null +++ b/Zend/tests/return_types/037.phpt @@ -0,0 +1,11 @@ +--TEST-- +__debugInfo can only declare array as return type +--FILE-- +<?php +class Foo { + public function __debugInfo(): bool { + } +} +?> +--EXPECTF-- +Fatal error: Foo::__debugInfo(): Return type must be ?array when declared in %s on line %d diff --git a/Zend/tests/return_types/038.phpt b/Zend/tests/return_types/038.phpt new file mode 100644 index 0000000000..a51658c454 --- /dev/null +++ b/Zend/tests/return_types/038.phpt @@ -0,0 +1,10 @@ +--TEST-- +__serialize can only declare array as return type +--FILE-- +<?php +class Foo { + public function __serialize(): \stdClass {} +} +?> +--EXPECTF-- +Fatal error: Foo::__serialize(): Return type must be array when declared in %s on line %d diff --git a/Zend/tests/return_types/039.phpt b/Zend/tests/return_types/039.phpt new file mode 100644 index 0000000000..15a420757c --- /dev/null +++ b/Zend/tests/return_types/039.phpt @@ -0,0 +1,10 @@ +--TEST-- +__unserialize can only declare void return +--FILE-- +<?php +class Foo { + public function __unserialize(array $data): array {} +} +?> +--EXPECTF-- +Fatal error: Foo::__unserialize(): Return type must be void when declared in %s on line %d diff --git a/Zend/tests/return_types/040.phpt b/Zend/tests/return_types/040.phpt new file mode 100644 index 0000000000..736a400f44 --- /dev/null +++ b/Zend/tests/return_types/040.phpt @@ -0,0 +1,10 @@ +--TEST-- +__sleep can only declare return as array +--FILE-- +<?php +class Foo { + public function __sleep(): bool|int {} +} +?> +--EXPECTF-- +Fatal error: Foo::__sleep(): Return type must be array when declared in %s on line %d diff --git a/Zend/tests/return_types/041.phpt b/Zend/tests/return_types/041.phpt new file mode 100644 index 0000000000..783e1444bc --- /dev/null +++ b/Zend/tests/return_types/041.phpt @@ -0,0 +1,10 @@ +--TEST-- +__wakeup can only declare return void +--FILE-- +<?php +class Foo { + public function __wakeup(): bool {} +} +?> +--EXPECTF-- +Fatal error: Foo::__wakeup(): Return type must be void when declared in %s on line %d diff --git a/Zend/tests/return_types/042.phpt b/Zend/tests/return_types/042.phpt new file mode 100644 index 0000000000..069e0228ff --- /dev/null +++ b/Zend/tests/return_types/042.phpt @@ -0,0 +1,24 @@ +--TEST-- +__debugInfo can declare union return type +--FILE-- +<?php +class UnionType { + public function __debugInfo(): array|null {} +} + +class UnionType2 { + public function __debugInfo(): null|array {} +} + +class UnionTypeOldStyle { + public function __debugInfo(): ?array {} +} + +class JustAnArray { + public function __debugInfo(): array {} +} + +echo 'No problems!'; +?> +--EXPECT-- +No problems! diff --git a/Zend/tests/return_types/043.phpt b/Zend/tests/return_types/043.phpt new file mode 100644 index 0000000000..ecc5660c62 --- /dev/null +++ b/Zend/tests/return_types/043.phpt @@ -0,0 +1,29 @@ +--TEST-- +Some magic methods can declare mixed return type +--FILE-- +<?php +class Foo { + public function __get($name): bool {} + public function __call($name, $args): string {} + public static function __callStatic($name, $args): self {} + public function __invoke(): self {} +} + +class Bar { + public function __get($name): string|array {} + public function __call($name, $args): int|float {} + public static function __callStatic($name, $args): ?object {} + public function __invoke(): Foo|int {} +} + +class Baz { + public function __get($name): mixed {} + public function __call($name, $args): mixed {} + public static function __callStatic($name, $args): mixed {} + public function __invoke(): mixed {} +} + +echo 'Okay!'; +?> +--EXPECT-- +Okay! diff --git a/Zend/tests/return_types/044.phpt b/Zend/tests/return_types/044.phpt new file mode 100644 index 0000000000..3b708a05a7 --- /dev/null +++ b/Zend/tests/return_types/044.phpt @@ -0,0 +1,10 @@ +--TEST-- +__set_state can only declare object as return +--FILE-- +<?php +class Foo { + public static function __set_state($properties): bool {} +} +?> +--EXPECTF-- +Fatal error: Foo::__set_state(): Return type must be object when declared in %s on line %d diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 62387d1be5..1b00e51416 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2048,6 +2048,31 @@ static void zend_check_magic_method_args( } } +static void zend_check_magic_method_arg_type(uint32_t arg_num, const zend_class_entry *ce, const zend_function *fptr, int error_type, int arg_type) +{ + if ( + ZEND_TYPE_IS_SET(fptr->common.arg_info[arg_num].type) + && !(ZEND_TYPE_FULL_MASK(fptr->common.arg_info[arg_num].type) & arg_type) + ) { + zend_error(error_type, "%s::%s(): Parameter #%d ($%s) must be of type %s when declared", + ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name), + arg_num + 1, ZSTR_VAL(fptr->common.arg_info[arg_num].name), + ZSTR_VAL(zend_type_to_string((zend_type) ZEND_TYPE_INIT_MASK(arg_type)))); + } +} + +static void zend_check_magic_method_return_type(const zend_class_entry *ce, const zend_function *fptr, int error_type, int return_type) +{ + if ( + (fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) + && (ZEND_TYPE_FULL_MASK(fptr->common.arg_info[-1].type) & ~return_type) + ) { + zend_error(error_type, "%s::%s(): Return type must be %s when declared", + ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name), + ZSTR_VAL(zend_type_to_string((zend_type) ZEND_TYPE_INIT_MASK(return_type)))); + } +} + static void zend_check_magic_method_non_static( const zend_class_entry *ce, const zend_function *fptr, int error_type) { @@ -2102,31 +2127,42 @@ ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce, } else if (zend_string_equals_literal(lcname, ZEND_CLONE_FUNC_NAME)) { zend_check_magic_method_args(0, ce, fptr, error_type); zend_check_magic_method_non_static(ce, fptr, error_type); - zend_check_magic_method_no_return_type(ce, fptr, error_type); + zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_VOID); } else if (zend_string_equals_literal(lcname, ZEND_GET_FUNC_NAME)) { zend_check_magic_method_args(1, ce, fptr, error_type); zend_check_magic_method_non_static(ce, fptr, error_type); zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_STRING); } else if (zend_string_equals_literal(lcname, ZEND_SET_FUNC_NAME)) { zend_check_magic_method_args(2, ce, fptr, error_type); zend_check_magic_method_non_static(ce, fptr, error_type); zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_STRING); + zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_VOID); } else if (zend_string_equals_literal(lcname, ZEND_UNSET_FUNC_NAME)) { zend_check_magic_method_args(1, ce, fptr, error_type); zend_check_magic_method_non_static(ce, fptr, error_type); zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_STRING); + zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_VOID); } else if (zend_string_equals_literal(lcname, ZEND_ISSET_FUNC_NAME)) { zend_check_magic_method_args(1, ce, fptr, error_type); zend_check_magic_method_non_static(ce, fptr, error_type); zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_STRING); + zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_BOOL); } else if (zend_string_equals_literal(lcname, ZEND_CALL_FUNC_NAME)) { zend_check_magic_method_args(2, ce, fptr, error_type); zend_check_magic_method_non_static(ce, fptr, error_type); zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_STRING); + zend_check_magic_method_arg_type(1, ce, fptr, error_type, MAY_BE_ARRAY); } else if (zend_string_equals_literal(lcname, ZEND_CALLSTATIC_FUNC_NAME)) { zend_check_magic_method_args(2, ce, fptr, error_type); zend_check_magic_method_static(ce, fptr, error_type); zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_STRING); + zend_check_magic_method_arg_type(1, ce, fptr, error_type, MAY_BE_ARRAY); } else if (zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_NAME)) { zend_check_magic_method_args(0, ce, fptr, error_type); zend_check_magic_method_non_static(ce, fptr, error_type); @@ -2135,21 +2171,36 @@ ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce, zend_check_magic_method_args(0, ce, fptr, error_type); zend_check_magic_method_non_static(ce, fptr, error_type); zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_return_type(ce, fptr, error_type, (MAY_BE_ARRAY | MAY_BE_NULL)); } else if (zend_string_equals_literal(lcname, "__serialize")) { zend_check_magic_method_args(0, ce, fptr, error_type); zend_check_magic_method_non_static(ce, fptr, error_type); zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_ARRAY); } else if (zend_string_equals_literal(lcname, "__unserialize")) { zend_check_magic_method_args(1, ce, fptr, error_type); zend_check_magic_method_non_static(ce, fptr, error_type); zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_ARRAY); + zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_VOID); } else if (zend_string_equals_literal(lcname, "__set_state")) { zend_check_magic_method_args(1, ce, fptr, error_type); zend_check_magic_method_static(ce, fptr, error_type); zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_OBJECT); } else if (zend_string_equals_literal(lcname, "__invoke")) { zend_check_magic_method_non_static(ce, fptr, error_type); zend_check_magic_method_public(ce, fptr, error_type); + } else if (zend_string_equals_literal(lcname, "__sleep")) { + zend_check_magic_method_args(0, ce, fptr, error_type); + zend_check_magic_method_non_static(ce, fptr, error_type); + zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_ARRAY); + } else if (zend_string_equals_literal(lcname, "__wakeup")) { + zend_check_magic_method_args(0, ce, fptr, error_type); + zend_check_magic_method_non_static(ce, fptr, error_type); + zend_check_magic_method_public(ce, fptr, error_type); + zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_VOID); } } /* }}} */ diff --git a/ext/reflection/tests/ReflectionMethod_getModifiers_basic.phpt b/ext/reflection/tests/ReflectionMethod_getModifiers_basic.phpt index 6e0a0645c5..c5fe6aa41a 100644 --- a/ext/reflection/tests/ReflectionMethod_getModifiers_basic.phpt +++ b/ext/reflection/tests/ReflectionMethod_getModifiers_basic.phpt @@ -32,10 +32,14 @@ class TestClass public final function fin() {} + public function __construct() {} + public function __destruct() {} public function __call($a, $b) {} + public static function __callStatic($a, $b) {} + public function __clone() {} public function __get($a) {} @@ -44,6 +48,8 @@ class TestClass public function __unset($a) {} + public function __invoke() {} + public function __isset($a) {} public function __tostring() {} @@ -55,6 +61,12 @@ class TestClass public static function __set_state($a) {} public function __autoload() {} + + public function __serialize() {} + + public function __unserialize($data) {} + + public function __debugInfo() {} } class DerivedClass extends TestClass {} @@ -102,6 +114,10 @@ Modifiers for method TestClass::fin(): 0x00000021 +Modifiers for method TestClass::__construct(): +0x00000001 + + Modifiers for method TestClass::__destruct(): 0x00000001 @@ -110,6 +126,10 @@ Modifiers for method TestClass::__call(): 0x00000001 +Modifiers for method TestClass::__callStatic(): +0x00000011 + + Modifiers for method TestClass::__clone(): 0x00000001 @@ -126,6 +146,10 @@ Modifiers for method TestClass::__unset(): 0x00000001 +Modifiers for method TestClass::__invoke(): +0x00000001 + + Modifiers for method TestClass::__isset(): 0x00000001 @@ -150,6 +174,18 @@ Modifiers for method TestClass::__autoload(): 0x00000001 +Modifiers for method TestClass::__serialize(): +0x00000001 + + +Modifiers for method TestClass::__unserialize(): +0x00000001 + + +Modifiers for method TestClass::__debugInfo(): +0x00000001 + + Modifiers for method TestClass::foo(): 0x00000001 @@ -166,6 +202,10 @@ Modifiers for method TestClass::fin(): 0x00000021 +Modifiers for method TestClass::__construct(): +0x00000001 + + Modifiers for method TestClass::__destruct(): 0x00000001 @@ -174,6 +214,10 @@ Modifiers for method TestClass::__call(): 0x00000001 +Modifiers for method TestClass::__callStatic(): +0x00000011 + + Modifiers for method TestClass::__clone(): 0x00000001 @@ -190,6 +234,10 @@ Modifiers for method TestClass::__unset(): 0x00000001 +Modifiers for method TestClass::__invoke(): +0x00000001 + + Modifiers for method TestClass::__isset(): 0x00000001 @@ -214,6 +262,18 @@ Modifiers for method TestClass::__autoload(): 0x00000001 +Modifiers for method TestClass::__serialize(): +0x00000001 + + +Modifiers for method TestClass::__unserialize(): +0x00000001 + + +Modifiers for method TestClass::__debugInfo(): +0x00000001 + + Modifiers for method TestInterface::int(): 0x00000041 |