2017-04-03 86 views
3

如何在抽象類上提示靜態單例返回方法,該方法返回擴展調用類的實例?類型暗示抽象類單例

例如,讓我們來看看下面的代碼:

<?php 

abstract class Foo { 

    /** @return Foo */ 
    public function init() { 
     static $instance; 

     if (is_null($instance)) { 
      $class = get_called_class(); 
      $instance = new $class(); 
     } 

     return $instance; 
    } 

} 

class Bar extends Foo { 

    public $name = "Bar name"; 

} 

class Baz extends Foo { 

    public $age = 42; 

} 

我的本意是工具,如PhpStorm明白Bar::init()返回Bar類型的對象和Baz::init()返回Baz類型的對象。因此,例如,從Baz::init()方法創建的對象將自動完成name屬性,但不會自動完成age屬性。

顯然,當前類型提示@return Foo是錯誤的,因爲該方法永遠不會返回抽象類的對象實例。

+1

'@return Foo'沒有錯,因爲函數返回的是一個'instanceof Foo'的對象,即使該對象是'Foo'的子元素,但是如果你想要一個準確的類提示,你可能會逃脫'@return static'(也許)。而且這一切都是IDE提示,所以它也取決於你的IDE足夠聰明以理解它的含義。 – apokryfos

+0

@apokryfos:謝謝。事實上,我曾考慮在該問題中添加一個PhpStorm標籤。 – dotancohen

+0

爲什麼你想讓你的代碼在每次運行中重構? –

回答

3

所以@return static將在這種情況下工作PHPStorm。 這是最簡單的選項,並將提供你在找什麼。

(可選)您可以對類使用@method批註,但這是非常手動的,需要爲每個類完成。在PHPStorm中這種方法還有一個奇怪的地方,如果你導航到init()方法(ctrl + click或w/e),它將首先導航到這個註解。然而,這是怎麼看起來:

/** 
* @method Bar init() 
*/ 
class Baz extends Foo 
{ 
} 

。可選作爲最後的手段 - 我真的不認爲你會需要它,但它是爲了完整性。像擴展常規方法一樣,擴展該方法並添加返回註釋。

/** 
* @return Baz 
*/ 
public function init() 
{ 
    return parent::init(); 
} 
+0

謝謝!事實上,擴展該方法來註釋它是我想到的一種解決方案,但感覺這是一種方法來實施。 – dotancohen

+0

很高興這有幫助。當使用'php7 +'時,你可能會發現自己擴展方法來改變類型提示'init():Baz'。看起來毫無意義,但它確實增加了運行時驗證,這很方便。 –

+0

顯然,在php7中,以下內容無效:'init():static'。有使用運行時提示的解決方案嗎? – dotancohen

1

你可以試試這個:

abstract class Foo { 

    /** @return static */ 
    public function init() { 
     static $instance; 

     if (is_null($instance)) { 
      $class = get_called_class(); 
      $instance = new $class(); 
     } 

     return $instance; 
    } 

} 

這可能需要PhpStorm要建立與PHP 5.3+類型提示工作。