]> granicus.if.org Git - php/commitdiff
Ensure correct signatures for magic methods
authorGabriel Caruso <carusogabriel34@gmail.com>
Fri, 31 May 2019 03:45:32 +0000 (00:45 -0300)
committerGabriel Caruso <carusogabriel34@gmail.com>
Sat, 1 Aug 2020 23:29:56 +0000 (01:29 +0200)
30 files changed:
UPGRADING
Zend/tests/magic_methods_011.phpt [new file with mode: 0644]
Zend/tests/magic_methods_012.phpt [new file with mode: 0644]
Zend/tests/magic_methods_013.phpt [new file with mode: 0644]
Zend/tests/magic_methods_014.phpt [new file with mode: 0644]
Zend/tests/magic_methods_015.phpt [new file with mode: 0644]
Zend/tests/magic_methods_016.phpt [new file with mode: 0644]
Zend/tests/magic_methods_017.phpt [new file with mode: 0644]
Zend/tests/magic_methods_018.phpt [new file with mode: 0644]
Zend/tests/magic_methods_019.phpt [new file with mode: 0644]
Zend/tests/magic_methods_inheritance_rules.phpt [new file with mode: 0644]
Zend/tests/magic_methods_inheritance_rules_non_trivial_01.phpt [new file with mode: 0644]
Zend/tests/magic_methods_inheritance_rules_non_trivial_02.phpt [new file with mode: 0644]
Zend/tests/magic_methods_sleep.phpt [new file with mode: 0644]
Zend/tests/magic_methods_wakeup.phpt [new file with mode: 0644]
Zend/tests/return_types/019.phpt
Zend/tests/return_types/033.phpt [new file with mode: 0644]
Zend/tests/return_types/034.phpt [new file with mode: 0644]
Zend/tests/return_types/035.phpt [new file with mode: 0644]
Zend/tests/return_types/036.phpt [new file with mode: 0644]
Zend/tests/return_types/037.phpt [new file with mode: 0644]
Zend/tests/return_types/038.phpt [new file with mode: 0644]
Zend/tests/return_types/039.phpt [new file with mode: 0644]
Zend/tests/return_types/040.phpt [new file with mode: 0644]
Zend/tests/return_types/041.phpt [new file with mode: 0644]
Zend/tests/return_types/042.phpt [new file with mode: 0644]
Zend/tests/return_types/043.phpt [new file with mode: 0644]
Zend/tests/return_types/044.phpt [new file with mode: 0644]
Zend/zend_API.c
ext/reflection/tests/ReflectionMethod_getModifiers_basic.phpt

index d473c2609eecb6b9c560b9eb468258d7262cfc7b..d4ddcede72fa23c90bd073f8aa16c902d1f23dcc 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -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 (file)
index 0000000..5ce536a
--- /dev/null
@@ -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 (file)
index 0000000..4ac3952
--- /dev/null
@@ -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 (file)
index 0000000..03a4fb7
--- /dev/null
@@ -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 (file)
index 0000000..783b600
--- /dev/null
@@ -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 (file)
index 0000000..d5e93c9
--- /dev/null
@@ -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 (file)
index 0000000..a0ac45e
--- /dev/null
@@ -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 (file)
index 0000000..9afb089
--- /dev/null
@@ -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 (file)
index 0000000..faddd3c
--- /dev/null
@@ -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 (file)
index 0000000..85823e6
--- /dev/null
@@ -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 (file)
index 0000000..e91fdc7
--- /dev/null
@@ -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 (file)
index 0000000..a57c8b7
--- /dev/null
@@ -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 (file)
index 0000000..72c20a7
--- /dev/null
@@ -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 (file)
index 0000000..593d8fc
--- /dev/null
@@ -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 (file)
index 0000000..f4edb33
--- /dev/null
@@ -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
index 4be32b24741d6a383527c666a310c29ba955a240..652548c3f93c194908b1cecfff9e5729db8e45db 100644 (file)
@@ -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 (file)
index 0000000..e725465
--- /dev/null
@@ -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 (file)
index 0000000..5032420
--- /dev/null
@@ -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 (file)
index 0000000..fa2d331
--- /dev/null
@@ -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 (file)
index 0000000..2f0847f
--- /dev/null
@@ -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 (file)
index 0000000..34569e4
--- /dev/null
@@ -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 (file)
index 0000000..a51658c
--- /dev/null
@@ -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 (file)
index 0000000..15a4207
--- /dev/null
@@ -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 (file)
index 0000000..736a400
--- /dev/null
@@ -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 (file)
index 0000000..783e144
--- /dev/null
@@ -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 (file)
index 0000000..069e022
--- /dev/null
@@ -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 (file)
index 0000000..ecc5660
--- /dev/null
@@ -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 (file)
index 0000000..3b708a0
--- /dev/null
@@ -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
index 62387d1be5d41d37206cdc29d19e45c55b8fd6cd..1b00e51416a32631066cad5df7e690991fa5c306 100644 (file)
@@ -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);
        }
 }
 /* }}} */
index 6e0a0645c5441b5d8c08e62ccf2a3be50b4e27ae..c5fe6aa41a2f3b85a2e13c8ba4a73dcd881b267c 100644 (file)
@@ -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