Jak funguje @return $this ve vašem IDE?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
petr.pavel
Člen | 535
+
+3
-

Současné anotace v Nette\Forms\Controls\BaseControl způsobují, že po zavolání třeba setRequired() PhpStorm začne považovat RadioList za BaseControl a označí mi následující volání getSeparatorPrototype() jako neplatné. Situací je víc, tohle je jen příklad.

Řešením je anotaci @return self nahradit anotací @return $this nebo @return static. Je ale potřeba zjistit, jak jsou na tom ostatní IDE a ApiGen. Prosím vás tedy o pomoc.

Použijte následující kód:

<?php
class A {
  /**
   * @return self
   */
  public function jedna() {}
}
class B extends A {
  public function dva() {}
}

$b = new B;
$b->jedna()->dva();
?>

Pokud vaše IDE rovnou neoznačí volání dva() jako neplatné, radši vyzkoušejte napovídání, abyste měli jistotu, že opravdu $b považuje za B.
Napište tedy $b->dv a CTRL+mezerník (nebo co máte pro doplňování názvu metody).

Vyzkoušené editory budu doplňovat sem. Pomlčka znamená, že IDE pro danou anotaci nenapovídá metodu dva().

PhpStorm 8.0.1, 8.0.2
@return self
@return static ano
@return $this ano
@return this – (v anotaci označí this jako neplatnou hodnotu)
Eclipse 3.7 Indigo +PDT (distribuce od Zend s názvem Eclipse for PHP Developers 3.0.2)
@return self ano (chápe jako static, tj. třídu potomka)
@return static
@return $this
@return this
Eclipse 4.5 Mars  
@return self ano (chápe jako static)
@return static
@return $this
@return this
NetBeans 8.0.1  
@return self ano
@return static ano
@return $this
@return this ano
Nusphere PhpEd 15  
@return self
@return static ano
@return $this
@return this – (považuje this za třídu)
Sublime Text 3 + SublimeCodeIntel 2.0.6  
@return self
@return static
@return $this
@return this
ApiGen 4.0.0-RC4  
@return self ano (typ návratové hodnoty A->jedna() uvede jako A, jinak to ani nejde)
@return static – (uvede doslovně jako static)
@return $this ? (uvede mixed; nevím, jak hodnotit)
@return this – (uvede doslovně jako this)

Zatím to vypadá dost beznadějně, ale Eclipse 3.7 Indigo je skutečně archaická verze, současná je 4.4 Luna (mezitím jsou dvě jiné velké verze).

Takže teď je to na vás, předem díky.

Edit po doplnění ApiGenu:
Až teď mi došlo, že ApiGen bude při return $this; v PHP kódu volaném potomkem vždycky lhát nebo mlžit – protože nemůže jinak. Můžeme si jen pomocí anotace vybrat, jestli chceme aby lhal tím, že uvede svou třídu (přestože se vrací třída potomka) nebo mlžil pomocí mixed, které je sice pravda, ale informačně k ničemu.

Editoval petr.pavel (17. 12. 2014 17:44)

Xethilos
Člen | 19
+
0
-

NetBeans 8.0.1:

self – Ano
static – Ano
$this – Ne
this – Chování jako static

petr.pavel
Člen | 535
+
0
-

Díky @Xethilos, doplněno. Používáte někdo novější Eclipse? Co takhle Komodo nebo phpDesigner? Něco jiného?

Beru i chytré textové editory s pluginy pro PHP, chci prostě získat přehled. I o tom, co tady kdo v současnosti používá.

jiri.pudil
Nette Blogger | 1032
+
0
-

Co jsem narychlo vyzkoušel apigen (4.0.0-RC4), poradí si jenom se self (v tom smyslu, že si to přeloží na aktuální třídu), static a this přepíše verbatim a místo $this dosadí mixed.

Jan Tvrdík
Nette guru | 2595
+
0
-

Zkusil jsem Eclipse Mars (4.5) a nic jiného, kromě self nepodporuje, přičemž self chápe jako static, takže následující kód funguje bez problému:

$input = new Nette\Forms\Controls\RadioList();
$input->setRequired(TRUE)->getSeparatorPrototype();
petr.pavel
Člen | 535
+
0
-

@jiri.pudil Až teď mi došlo, co vlastně můžeme od ApiGenu čekat. Doplnil jsem nahoru komentář a zajímal by mě tvůj názor (i ostatních).

@JanTvrdík Díky! Zdá se, že od verze 3.7 se tedy nic nezměnilo :-(
„Funguje bez problémů“ tedy znamená, že metodu getSeparatorPrototype() napoví, ano? Verze 3.7 mi nijak nezvýrazňovala metody, které u třídy nenašla, takže to šlo poznat jedině přes napovídání/doplňování při psaní.

Jan Tvrdík
Nette guru | 2595
+
+3
-

ad ApiGen – když tam doplní aktuální třídu, tak rozhodně nelže. Všechny navrácené hodnoty budou instancí (instanceof) té dané třídy. Kdyby PHP byl staticky typovaný jazyk, tak by jako typ návratové hodnoty byla taky uvedena samotná třída.

jannek19
Člen | 47
+
0
-

Přikládám výsledky ze Sublime Text 3 se SublimeCodeIntel pluginem (v2.0.6+st3)

  • self – ne
  • static – ne
  • $this – považuje za neplatnou hodnotu (nenapoví vůbec nic)
  • this – ne
petr.pavel
Člen | 535
+
0
-

@jannek19: Díky za účast. Výsledek mě dost překvapil, takže jsem ho pro jistotu ověřil. Fakt že jo, dokud do anotace nenapíšu @return B, tak mi ST3 nerozpozná dva jako funkci. To je teda materiál…

David Grudl
Nette Core | 8228
+
+5
-

Pár poznámek:

  1. jelikož jde o type hinting, tedy napovídání podle typů, je @return $this nesmysl, který by vůbec neměly editory podporovat
  2. protože this není klíčové slovo a můžu klidně tak pojmenovat třídu, neměly by editory v žádném případě podporovat @return this.
  3. nenašel jsem téměř žádnou knihovnu, která by používala @return static
  4. @return self je poměrně běžně používáno ve smyslu fluent interface (ZF2), tady by se mohl „standard“ přizpůsobit

(doplnil jsem do přehledu Nusphere PhpEd 15)

pepakriz
Člen | 246
+
0
-

PhpStorm 8.0.2:

  • self – ano (chápe jako self)
  • static – ano (chápe jako static)
  • $this – ano (chápe jako static)
  • this – ne – podle mě to bere jako normální název třídy
petr.pavel
Člen | 535
+
0
-

@pepakriz: Díky za ověření, akorát „self“ má mít „ne“ (tj. „-“), protože se snažíme zjistit, které hodnoty jsou interpretovány jako static, nikoliv které hodnoty jsou podporovány obecně.

Jan Tvrdík
Nette guru | 2595
+
+1
-

Doplním jak se k tomu staví ostatní frameworky (prošel jsem náhodné kusy kódu):

  • Laravel používá zápis return $this
  • Symfony používá zápis return ClassName + výjimečně return $this
  • Zend používá return ClassName
David Grudl
Nette Core | 8228
+
0
-

V PHP 7 funguje jen „return“ self, static háže parse error. http://3v4l.org/TvJjC

Jan Tvrdík
Nette guru | 2595
+
0
-

Btw, interesting thing is that return self works as static and static is parse error http://3v4l.org/TvJjC. This is the end of discussion about @return self vs static.

return self funguje jako return self (tj. stejně jako return X v odkázaném příkladu), ale pochopitelně můžeš vrátit o podtyp.

Kdyby to fungovalo jako return static, tak by prošlo http://3v4l.org/vpMAS. Je to z toho důvodu, že PHP nepodporuje „Covariant return types“. V původním RFC to sice bylo, ale pak kluci z internals zjistili, že vzhledem k architektuře PHP to nejde naimplementovat.

David Grudl
Nette Core | 8228
+
0
-

Jo, máš pravdu, self nefunguje jako static.

petr.pavel
Člen | 535
+
0
-

Sorry, ztrácím se v tom, co jste chtěli říct, kluci ( @DavidGrudl a @JanTvrdík ). Pochopil jsem, že David upozornil na novou fíčuru PHP 7, která umožňuje definovat typ návratové hodnoty metody. Z typů, které tu probíráme zná pouze „self“ a rozumí pod tím objekt, přes nějž jsme metodu volali. Následující kód vrátí object(B)#1 (0) { }

<?php
class A { function test() : self { return $this; } }
class B extends A {}

$b = new B;
var_dump($b->test());
?>

Nevím, kde najít definici slova „static“, ale tohle vypadá jako to, o co mi v tomhle vlákně šlo.
Je mi jedno, co napíšeme do @return, já jen potřebuju, aby mi IDE (PhpStorm) napovídal potomky.

Honza pak upozornil, že návratovou hodnotu self nejde použít u přetěžovaných funkcí. Následující kód hodí chybu: `Fatal error: Declaration of B::test() must be compatible with A::test(): A `

<?php
class A { function test(): self { return $this; } }
class B extends A {	function test(): self { return $this; } }
?>

Takže to nakonec není ten static, o který mi v tomto vlákně šlo :-) Pochopil jsem to dobře?

Je z toho nějaký závěr? Jedeme dál přes PHPDoc a nadále se „static“ „self“?

Editoval petr.pavel (15. 8. 2015 14:22)

petr.pavel
Člen | 535
+
0
-

Jan Tvrdík napsal(a):

Doplním jak se k tomu staví ostatní frameworky (prošel jsem náhodné kusy kódu):

  • Laravel používá zápis return $this
  • Symfony používá zápis return ClassName + výjimečně return $this
  • Zend používá return ClassName

Díky! Díval ses na metody, které se běžně volají z potomků?

Když je v PHPDoc rodiče @return TridaRodice, tak si při volání $potomek->metoda() musí IDE myslet, že návratová hodnota je typu TridaRodice, ne? To mi nedává moc smysl…

David Grudl
Nette Core | 8228
+
+1
-

TridaRodice a self je z pohledu PHP to samé. To, co tě zajímá, je static.

Sám používám @return self ve smyslu @return static (jinak použiju return ClassName).

Diskuse je vlastně o tom, jestli nahradit @return self za @return static (ostatní varianty $this a this vůbec nepřipadají v úvahu, to první není typ a nelze použít pro return new static, to druhé představuje třídu s názvem this).

Nahradit by to v podstatě šlo, byť by bylo samozřejmě potřeba opravit ApiGen. (Zkomplikovalo by mi to život s PhpEd 8.1, který typu static nerozumí, což není podstatné, ale je to důvod, proč jsem takovou změnu sám neudělal.)

Nicméně přichází PHP 7, které umožňuje uvádět typy návratových hodnot, takže spousta anotací @return bude moci být nahrazena přímo kódem. A návratový typ může být jen self, nikoliv static.

Což dává smysl. Jenže tím se situace komplikuje ještě víc. Anotace @return static nemůže být plně nahrazena typehintem. Buď se na to rezignuje, nebo se bude kombinovat typehint s anotací, přičemž absolutně netušíme, jak takovou věc budou chápat editory.

Jinými slovy, situace se v případě PHP7 vrací na začátek.

Jan Tvrdík
Nette guru | 2595
+
+2
-

@DavidGrudl Pěkně jsi to shrnul.

přičemž absolutně netušíme, jak takovou věc budou chápat editory

Tak jsem zkusil, jak se momentálně chová PhpStorm 9.0.1:

class A
{
	public function declaredOnParent()
	{

	}


	public function fluentRealSelf(): self
	{
		return $this;
	}


	public function fluentNothing()
	{
		return $this;
	}


	/** @return self */
	public function fluentPhpDocSelf()
	{
		return $this;
	}


	/** @return static */
	public function fluentPhpDocStatic()
	{
		return $this;
	}


	/** @return $this */
	public function fluentPhpDocThis()
	{
		return $this;
	}


	/** @return self */
	public function fluentPhpDocSelfRealSelf(): self
	{
		return $this;
	}


	/** @return static */
	public function fluentPhpDocStaticRealSelf(): self
	{
		return $this;
	}


	/** @return $this */
	public function fluentPhpDocThisRealSelf(): self
	{
		return $this;
	}
}


class B extends A
{
	public function declaredOnChild()
	{

	}
}


$obj = new B();

// resolved as A -> ERROR
$obj->fluentRealSelf()->declaredOnChild();

// resolved as $this
$obj->fluentNothing()->declaredOnChild();

// resolved as A -> ERROR
$obj->fluentPhpDocSelf()->declaredOnChild();

// resolved as static
$obj->fluentPhpDocStatic()->declaredOnChild();

// resolved as $this
$obj->fluentPhpDocThis()->declaredOnChild();

// resolved as A -> ERROR
$obj->fluentPhpDocSelfRealSelf()->declaredOnChild();

// resolved as A|static
$obj->fluentPhpDocStaticRealSelf()->declaredOnChild();

// resolved as A|$this
$obj->fluentPhpDocThisRealSelf()->declaredOnChild();

  nothing self
nothing $this self
self self self
static static self|static
$this $this self|$this
petr.pavel
Člen | 535
+
-2
-

David Grudl napsal(a):
(ostatní varianty $this a this vůbec nepřipadají v úvahu…)

To záleží, jak budeme chápat syntaxi PHPDoc pro @return. Existuje někde oficiální definice PHPDoc? Mám dojem, že ne. Takže je to de facto standard odvozený z jiného jazyka… a proč si ho nepřiohnout. Vnímám to tak, že phpdoc.org je o programu a o tom, co tento program podporuje, ne o standardu.

Ty předpokládáš @return <název střídy|self|static>. Pokud bychom byli ze srdce přesvědčení, že ten standard by měl být rozšířen na @return <název střídy|self|static|brundibal>, tak proč ne? Samozřejmě, je tu otázka, jak tento „rozšířený standard“ budou podporovat ostatní.

přičemž absolutně netušíme, jak takovou věc budou chápat editory.

Přesně tak. Už teď je v tom roky bordel, těžko říct, jestli PHP 7 self bude IDE motivovat k nějaké snaze o sjednocení.

Mě z toho vychází, že kromě „počkáme a uvidíme“ můžeme taky aktivně zaujmout stanovisko :-) a pokusit se ho protlačit. Přeci jen, třeba právě teď zrovna někdo z PhpEd brouzdá po webu a říká si „Safra, co s tím @return self, mrknu se, jak to dělají jinde. Hele Nette, to je pořádný framework…“

Rád bych ti slíbil, že ti pro to do PhpEd napíšu doplněk, ale to nedám. :-(

petr.pavel
Člen | 535
+
0
-

Koukám, tady se už někdo pokoušel dát dohromady vývojáře IDE:
https://groups.google.com/forum/#…

Poslední zpráva z 10.10.13:

Got some positive responses from many projects. Hope it will result in a good discussion and consistent adoption of things such as „@return static“.