php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #63659 Type hint 'self' means plain 'self' instead of original target class
Submitted: 2012-11-30 13:58 UTC Modified: 2015-03-07 10:50 UTC
Votes:33
Avg. Score:3.0 ± 0.0
Reproduced:0 of 3 (0.0%)
From: vovan-ve at yandex dot ru Assigned: reeze (profile)
Status: Closed Package: Class/Object related
PHP Version: Irrelevant OS:
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: vovan-ve at yandex dot ru
New email:
PHP Version: OS:

 

 [2012-11-30 13:58 UTC] vovan-ve at yandex dot ru
Description:
------------
It seems to me, there is some unclear situation with keywords «self»
(and «parent»). At least this keywords has no detailed documentation.

Imaging following interface:

	interface IFoo {
		public function lorem(IFoo $foo);
		public function ipsum(self $foo);
	}

The first method lorem() wants an implementation of IFoo as argument. The one
problem here is a duplication of the name IFoo inside itself. Usage of keyword
«self» should prevent this "problem", but in theory only.

The second method ipsum() extects an instance of... of what? In fact, it wants
an instance of «self» - that is an instance of implementation class, which
implements or even overrides the method later.

The problem is the fact, that keyword «self» means SELF, not a class or
an interface, there it is writen. We cannot change «self» to «IFoo» in
implementation:

	interface IFoo {
		public function ipsum(self $foo);
	}

	class Fail implements IFoo {
		public function ipsum(IFoo $foo) {
		}
	}
	// Error: Fail::ipsum() must be compatible with IFoo::ipsum()

The ReflectionClass shows «IFoo», «self» and «parent» for corresponding methods:

	interface IFoo {
		public function lorem(IFoo $foo);
		public function ipsum(self $foo);
		public function dolor(parent $foo);
	}

	$ref = new ReflectionClass('IFoo');
	echo $ref;

Output:

    Method [ <user> abstract public method lorem ] {
      - Parameters [1] {
        Parameter #0 [ <required> IFoo $foo ]
      }
    }
    Method [ <user> abstract public method ipsum ] {
      - Parameters [1] {
        Parameter #0 [ <required> self $foo ]
      }
    }
    Method [ <user> abstract public method dolor ] {
      - Parameters [1] {
        Parameter #0 [ <required> parent $foo ]
      }
    }

When we write «self» somewhere, we mean that thing, where «self» is writen.
I think, that method ipsum() should be compiled to receive instance of IFoo
and nothing else. The method dolor() shoult to emit fatal error, because IFoo
has no parent.

If I mistake with that deep meaning if the keywords «self» and «parent»,
and this isn't a bug, I sure this keywords should be documented properly.

Test script:
---------------
interface IFoo {
	public function ipsum(self $foo);
}

class Bar implements IFoo {
	public function ipsum(self $foo) {
		echo __METHOD__, "(", get_class($foo), ")\n";
	}
}

class Baz extends Bar {
	public function ipsum(self $foo) {
		echo __METHOD__, "(", get_class($foo), ")\n";
	}
}

class Lol implements IFoo {
	public function ipsum(self $foo) {
		echo __METHOD__, "(", get_class($foo), ")\n";
	}
}

# test objects
$bar = new Bar();
$baz = new Baz();
$lol = new Lol();

# lets try everything

# IFoo::ipsum(self $foo)

# Bar::ipsum(self $foo)
$bar->ipsum($bar); # Bar::ipsum(Bar)
$bar->ipsum($baz); # Bar::ipsum(Baz)
$bar->ipsum($lol); # Error: Bar::ipsum() extects Bar, but Lol given

# Baz::ipsum(self $foo)
$baz->ipsum($bar); # Error: Baz::ipsum() extects Baz, but Bar given
$baz->ipsum($baz); # Baz::ipsum(Baz)
$baz->ipsum($lol); # Error: Baz::ipsum() extects Baz, but Lol given

# Lol::ipsum(self $foo)
$lol->ipsum($bar); # Error: Lol::ipsum() extects Lol, but Bar given
$lol->ipsum($baz); # Error: Lol::ipsum() extects Lol, but Baz given
$lol->ipsum($lol); # Lol::ipsum(Lol)

Expected result:
----------------
Bar::ipsum(Bar)
Bar::ipsum(Baz)
Bar::ipsum(Lol)
Baz::ipsum(Bar)
Baz::ipsum(Baz)
Baz::ipsum(Lol)
Lol::ipsum(Bar)
Lol::ipsum(Baz)
Lol::ipsum(Lol)

Actual result:
--------------
Bar::ipsum(Bar)
Bar::ipsum(Baz)
Catchable fatal error:  Argument 1 passed to Bar::ipsum() must be an instance of Bar, instance of Lol given, called in ... and defined ...


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2015-03-07 10:50 UTC] reeze@php.net
-Status: Open +Status: Closed -Assigned To: +Assigned To: reeze
 [2015-03-07 10:50 UTC] reeze@php.net
It has been fixed since 5.4.1   http://3v4l.org/9iTrD
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sun Dec 22 05:01:30 2024 UTC