Bug #75079 [Opn]: self keyword leads to incorrectly generated TypeError when in closure in trait
| From: | aidantwoods at gmail dot com | 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