Bug #75079 [Opn]: self keyword leads to incorrectly generated TypeError when in closure in trait

From: Date: Wed, 16 Aug 2017 18:24:54 +0000
Subject: Bug #75079 [Opn]: self keyword leads to incorrectly generated TypeError when in closure in trait
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-210695@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=75079&edit=1 ID: 75079 User updated by: aidantwoods at gmail dot com Reported by: aidantwoods at gmail dot com -Summary: self is only resolved once for closure in trait +Summary: self keyword leads to incorrectly generated TypeError when in closure in trait Status: Open Type: Bug Package: Class/Object related -Operating System: OSX; Kali Linux (Debian) +Operating System: Tested: OSX; Kali Linux (Debian) PHP Version: 7.1.8 Block user comment: N Private report: N New Comment: edit: summary Previous Comments: ------------------------------------------------------------------------ [2017-08-16 18:12:04] aidantwoods at gmail dot com Description: ------------ Traits are meant to be syntactic sugar for "copy-pasting" things into classes. As such, when the self keyword is used inside a trait, it does not resolve to the name of the trait, but rather resolves to be the name of the class in which the trait was used in. If the self keyword is used within a type hint in a closure that is used inside a trait, this closure does not appear to be re-resolved per inclusion. For example, from the test script included, it should not be possible for the closure to throw a TypeError in any circumstance (if a type error is to be thrown, it should be thrown by the outer method) public function selfDo(self ...$Selfs) { array_map( function (self $Self) : self { return $Self; }, $Selfs ); } As expected, when calling exclusively the following $Bar->selfDo($Bar, $Bar); No TypeError is thrown. Alternatively, when calling exclusively the following $Baz->selfDo($Baz, $Baz); Also no TypeError is thrown. The problem arises when calling one after the other (does not need to be immediately after). Depending on the order those last two lines of the test script are called in, you will see a different error thrown. In the order given, the following is generated (trimmed for brevity) Fatal error: Uncaught TypeError: Argument 1 passed to Baz::{closure}() must be an instance of Bar, instance of Baz given in[...] It seems that once the method is initially called, the self type hint in the closure in the trait resolves to be the name of the class in which it was used in (no bug here), the bug is that this initial class name is now permanently resolved as its current value in latter calls to the same method (from a different unrelated class). Test script: --------------- <?php trait Foo { public function selfDo(self ...$Selfs) { array_map( function (self $Self) : self { return $Self; }, $Selfs ); } } class Bar { use Foo; } class Baz { use Foo; } $Bar = new Bar; $Baz = new Baz; $Bar->selfDo($Bar, $Bar); $Baz->selfDo($Baz, $Baz); Actual result: -------------- Fatal error: Uncaught TypeError: Argument 1 passed to Baz::{closure}() must be an instance of Bar, instance of Baz given in /Users/Aidan/traits.php:8 Stack trace: #0 [internal function]: Baz->{closure}(Object(Baz)) #1 /Users/Aidan/traits.php(12): array_map(Object(Closure), Array) #2 /Users/Aidan/traits.php(31): Baz->selfDo(Object(Baz), Object(Baz)) #3 {main} thrown in /Users/Aidan/traits.php on line 8 ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=75079&edit=1

« previous php.bugs (#210695) next »