PHPDoctypes提示对象的数组?

所以,在PHPDoc中,可以在成员variables声明之上指定@var来提示其types。 然后IDE,为前。 PHPEd,将知道它正在使用什么types的对象,并将能够提供该variables的代码洞察力。

 <?php class Test { /** @var SomeObj */ private $someObjInstance; } ?> 

这很好,直到我需要做一样的对象数组,以便能够得到适当的提示,当我迭代这些对象后来。

那么,有没有办法声明一个PHPDoc标签来指定成员variables是SomeObj的数组? @var数组是不够的, @var array(SomeObj)似乎不是有效的,例如。

你可以做的最好的就是说,

 foreach ($Objs as $Obj) { /* @var $Obj Test */ // You should be able to get hinting after the preceding line if you type $Obj-> } 

我在Zend Studio中做了很多。 不知道其他编辑,但它应该工作。

在JetBrains的PhpStorm IDE中,可以使用/** @var SomeObj[] */ ,例如:

 /** * @return SomeObj[] */ function getSomeObjects() {...} 

phpdoc文档推荐这个方法:

指定包含单个types,Type定义通知读者每个数组元素的types。 然后,只有一个types被期望作为给定数组的元素。

例如: @return int[]

Netbeans暗示:

您可以在$users[0]->上获得代码完成,为$this->获得一个User类数组。

 /** * @var User[] */ var $users = array(); 

当你完成$this->...时,你也可以在类成员列表中看到数组的types$this->...

指定一个variables是一个对象数组:

 $needles = getAllNeedles(); /* @var $needles Needle[] */ $needles[1]->... //codehinting works 

这在Netbeans 7.2(我正在使用它)

也适用于:

 $needles = getAllNeedles(); /* @var $needles Needle[] */ foreach ($needles as $needle) { $needle->... //codehinting works } 

因此,在foreach使用声明是没有必要的。

PSR-5:PHPDoc提出了一种generics风格的表示法。

句法

 Type[] Type<Type> Type<Type[, Type]...> Type<Type[|Type]...> 

集合中的值可能甚至是另一个数组,甚至另一个集合。

 Type<Type<Type>> Type<Type<Type[, Type]...>> Type<Type<Type[|Type]...>> 

例子

 <?php $x = [new Name()]; /* @var $x Name[] */ $y = new Collection([new Name()]); /* @var $y Collection<Name> */ $a = new Collection(); $a[] = new Model_User(); $a->resetChanges(); $a[0]->name = "George"; $a->echoChanges(); /* @var $a Collection<Model_User> */ 

注意:如果您希望IDE执行代码辅助,那么关于IDE是否支持PHPDoc通用样式集合表示法也是另一个问题。

从我对这个问题的回答 。

我更喜欢读写干净的代码 – 正如罗伯特·C·马丁(Robert C. Martin)的“清洁代码”(Clean Code)所述。 遵守他的信条时,您不应该要求开发人员(作为您的API的用户)了解您的arrays的(内部)结构。

API用户可能会问:这是一个只有一维的数组吗? 对象是否在multidimensional array的各个层次上传播? 我需要访问所有对象多less个嵌套循环(foreach等)? 什么types的对象被“存储”在该数组中?

正如你所概述的,你想使用该数组(包含对象)作为一维数组。

正如Nishi所述,您可以使用:

 /** * @return SomeObj[] */ 

为了那个原因。

但是,请注意 – 这不是标准的docblock记法。 这个符号是由一些IDE生产者引入的。

好吧,好吧,作为一名开发人员,您知道“[]”绑定到PHP中的数组。 但是在正常的PHP环境中,“something []”意味着什么? “[]”是指:在“某物”内创build新的元素。 新元素可能是一切。 但是你想要expression的是:具有相同types的对象的数组,它是确切的types。 如您所见,IDE生产者引入了新的上下文。 一个新的环境,你必须学习。 其他PHP开发人员必须学习的新上下文(了解您的docblocks)。 不好的风格(!)。

因为你的数组有一个维度,所以你可能想把这个“数组对象”称为“列表”。 请注意,“列表”在其他编程语言中有非常特殊的含义。 例如,将其称为“集合”会更好。

请记住:您使用了一种编程语言,使您可以使用OOP的所有选项。 使用一个类而不是一个数组,让你的类可以像数组一样遍历。 例如:

 class orderCollection implements ArrayIterator 

或者,如果要将内部对象存储在multidimensional array/对象结构中的不同层上,请执行以下操作:

 class orderCollection implements RecursiveArrayIterator 

这个解决scheme用一个types为“orderCollection”的对象replace你的数组,但是到目前为止你的IDE中不要启用代码完成。 好的。 下一步:

用docblocks实现接口引入的方法 – 特别是:

 /** * [...] * @return Order */ orderCollection::current() /** * [...] * @return integer Eg database identifier of the order */ orderCollection::key() /** * [...] * @return Order */ orderCollection::offsetGet() 

不要忘记使用types提示:

 orderCollection::append(Order $order) orderCollection::offsetSet(Order $order) 

这个解决scheme停止引入了很多:

 /** @var $key ... */ /** @var $value ... */ 

遍及你的代码文件(例如循环内),就像Zahymaka用她/他的答案所证实的那样。 您的API用户不会被迫引入该文件块,以便完成代码。 只有一个地方有@返回尽可能减less冗余(@var)。 洒“与@var docBlocks”会使你的代码最糟糕的可读性。

最后你完成了。 看起来很难达到? 看起来像拿大锤打破坚果? 不是真的,因为你熟悉那个接口和干净的代码。 记住:你的源代码被写入一次/阅读许多。

如果您的IDE的代码完成无法使用此方法,请切换到更好的(例如IntelliJ IDEA,PhpStorm,Netbeans)或在IDE生产者的问题跟踪器上提出function请求。

感谢Christian Weiss(来自德国)成为我的教练,教给我这么棒的东西。 PS:在XING见我和他。

在NetBeans 7.0中(也可能更低),您可以像@return Text一样声明返回types“Text对象的数组”,代码提示将会工作:

编辑:更新与@Bob Fangerbuild议的例子

 /** * get all Tests * * @return Test|Array $tests */ public function getAllTexts(){ return array(new Test(), new Test()); } 

只是使用它:

 $tests = $controller->getAllTests(); //$tests-> //codehinting works! //$tests[0]-> //codehinting works! foreach($tests as $text){ //$test-> //codehinting works! } 

这不是完美的,但只是离开它只是“混合”,女巫没有带来任何价值。

缺点是你是被允许践踏arrays作为文本对象女巫会抛出错误。

正如DanielaWaranie在她的回答中提到的那样 – 在$ collectionObject中迭代$ items时,有一种方法可以指定$ item的types:将@return MyEntitiesClassName添加到current()以及其他返回值的IteratorArrayAccess方法。

繁荣! 没有必要在/** @var SomeObj[] $collectionObj */ foreach ,并且正确地使用集合对象,不需要使用特定方法返回集合,如@return SomeObj[]

我怀疑并不是所有的IDE都支持它,但是它在PhpStorm中工作得很好,这让我更开心。

例:

 Class MyCollection implements Countable, Iterator, ArrayAccess { /** * @return User */ public function current() { return $this->items[$this->cursor]; } //... implement rest of the required `interface` methods and your custom } 

我将添加张贴这个答案什么有用的

在我的情况下, current()interface方法的其余部分在Abstract -collection类中实现,我不知道最终将在集合中存储什么样的实体。

所以这里有一个诀窍:不要在抽象类中指定返回types,而@method在描述特定的集合类时使用PhpDoc的instuction @method

例:

 Class User { function printLogin() { echo $this->login; } } Abstract Class MyCollection implements Countable, Iterator, ArrayAccess { protected $items = []; public function current() { return $this->items[$this->cursor]; } //... implement rest of the required `interface` methods and your custom //... abstract methods which will be shared among child-classes } /** * @method User current() * ...rest of methods (for ArrayAccess) if needed */ Class UserCollection extends MyCollection { function add(User $user) { $this->items[] = $user; } // User collection specific methods... } 

现在,使用类:

 $collection = new UserCollection(); $collection->add(new User(1)); $collection->add(new User(2)); $collection->add(new User(3)); foreach ($collection as $user) { // IDE should `recognize` method `printLogin()` here! $user->printLogin(); } 

再一次:我怀疑并不是所有的IDE都支持它,但是PhpStorm却支持它。 尝试你的,发表评论的结果!

在Zend Studio中使用array[type]

在Zend Studio中, array[MyClass]或者array[int]或者甚至array[array[MyClass]]都很array[array[MyClass]]

问题是@var只能表示一个types – 不包含复杂的公式。 如果你有一个“Foo数组”的语法,为什么要在那里停下来,而不是添加一个“arrays数组,包含2 Foo的和三个酒吧”的语法? 我明白,一个元素列表可能比这个更通用,但这是一个滑坡。

就我个人而言,我曾多次使用@var Foo[]来表示“Foo的数组”,但IDE不支持它。

 <?php foreach($this->models as /** @var Model_Object_WheelModel */ $model): ?> <?php // Type hinting now works: $model->getImage(); ?> <?php endforeach; ?> 

我知道我迟到了,但最近我一直在解决这个问题。 我希望有人看到这个,因为接受的答案虽然是正确的,但并不是你能做到这一点的最好方法。 至less在PHPStorm中,我还没有testing过NetBeans。

最好的方法是扩展ArrayIterator类,而不是使用本地数组types。 这允许您在类级而不是实例级提示提示,这意味着您只需要PHPDoc一次,而不是在整个代码中(这不仅是凌乱和违反DRY,而且在涉及到时也可能有问题重构 – PHPStorm在重构时有一个缺lessPHPDoc的习惯)

见下面的代码:

 class MyObj { private $val; public function __construct($val) { $this->val = $val; } public function getter() { return $this->val; } } /** * @method MyObj current() */ class MyObjCollection extends ArrayIterator { public function __construct(Array $array = []) { foreach($array as $object) { if(!is_a($object, MyObj::class)) { throw new Exception('Invalid object passed to ' . __METHOD__ . ', expected type ' . MyObj::class); } } parent::__construct($array); } public function echoContents() { foreach($this as $key => $myObj) { echo $key . ': ' . $myObj->getter() . '<br>'; } } } $myObjCollection = new MyObjCollection([ new MyObj(1), new MyObj('foo'), new MyObj('blah'), new MyObj(23), new MyObj(array()) ]); $myObjCollection->echoContents(); 

这里的关键是PHPDoc @method MyObj current()覆盖从ArrayIterator( mixed )inheritance的返回types。 包含这个PHPDoc意味着当我们使用foreach($this as $myObj)迭代类属性时,我们在引用variables$myObj->...时获得代码完成$myObj->...

对我来说,这是实现这一点的最好方法(至less在PHP引入Typed Arrays之前,如果他们曾经这样做的话),因为我们在迭代类中声明了迭代器types,而不是遍布整个代码的类的实例。

我没有在这里展示扩展ArrayIterator的完整解决scheme,所以如果你使用这种技术,你可能还想:

  • 对于像offsetGet($index)next()这样的方法,根据需要包含其他类级的PHPDoc。
  • 从构造函数移动完整性检查is_a($object, MyObj::class)到一个私有方法
  • 调用这个(现在私人)健全检查方法重写,如offsetSet($index, $newval)append($value)

我发现了一些正在工作的东西,它可以挽救生命!

 private $userList = array(); $userList = User::fetchAll(); // now $userList is an array of User objects foreach ($userList as $user) { $user instanceof User; echo $user->getName(); }