Skip to content

[RFC] Ensure correct magic methods' signatures when typed #4177

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Zend/tests/magic_methods_011.phpt
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions Zend/tests/magic_methods_012.phpt
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions Zend/tests/magic_methods_013.phpt
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions Zend/tests/magic_methods_014.phpt
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions Zend/tests/magic_methods_015.phpt
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions Zend/tests/magic_methods_016.phpt
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions Zend/tests/magic_methods_017.phpt
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions Zend/tests/magic_methods_018.phpt
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions Zend/tests/magic_methods_019.phpt
Original file line number Diff line number Diff line change
@@ -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
70 changes: 70 additions & 0 deletions Zend/tests/magic_methods_inheritance_rules.phpt
Original file line number Diff line number Diff line change
@@ -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!
18 changes: 18 additions & 0 deletions Zend/tests/magic_methods_inheritance_rules_non_trivial_01.phpt
Original file line number Diff line number Diff line change
@@ -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
18 changes: 18 additions & 0 deletions Zend/tests/magic_methods_inheritance_rules_non_trivial_02.phpt
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions Zend/tests/magic_methods_sleep.phpt
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions Zend/tests/magic_methods_wakeup.phpt
Original file line number Diff line number Diff line change
@@ -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
5 changes: 3 additions & 2 deletions Zend/tests/return_types/019.phpt
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions Zend/tests/return_types/033.phpt
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions Zend/tests/return_types/034.phpt
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions Zend/tests/return_types/035.phpt
Original file line number Diff line number Diff line change
@@ -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
11 changes: 11 additions & 0 deletions Zend/tests/return_types/036.phpt
Original file line number Diff line number Diff line change
@@ -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
11 changes: 11 additions & 0 deletions Zend/tests/return_types/037.phpt
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions Zend/tests/return_types/038.phpt
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions Zend/tests/return_types/039.phpt
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions Zend/tests/return_types/040.phpt
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions Zend/tests/return_types/041.phpt
Original file line number Diff line number Diff line change
@@ -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
24 changes: 24 additions & 0 deletions Zend/tests/return_types/042.phpt
Original file line number Diff line number Diff line change
@@ -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!
29 changes: 29 additions & 0 deletions Zend/tests/return_types/043.phpt
Original file line number Diff line number Diff line change
@@ -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!
Loading