处理对象数组和智能感知
Handling array of object and intellisense
我发现很多时候我将自定义对象数组传递给函数进行处理。在我的函数中,我在访问内部 properties/methods.
之前检查以确保它是正确的 class
因为我正在使用一个数组,据我所知 PHP 没有任何类型化的通用列表,所以我不能使用类型提示,所以我的 IDE 中的智能感知不起作用并且代码检查抛出警告。
我遇到了一个旧的 post,它给出了加入这行代码的想法,以便在开发时让智能感知工作:
if (false) $myObj = new MyObject();
所以我最终得到了一个看起来像这样的函数:
function ProcessObjectArray(array $arrayOfObject)
{
foreach ($arrayOfObject as $key => $myObj) {
if (get_class($myObj) == 'MyNamespace\MyObject') {
if (false) $myObj = new MyObject();
// I can now access intellisense for MyObject in here
} else {
trigger_error('is not right object');
}
}
}
这似乎有点奇怪,所以我想知道这是否表明我没有以最佳方式处理对象数组,或者是否有更好的方式让我的智能感知工作。我查看了 arrayobject 接口,看看是否可以创建一个 class 实现 arrayobject 来保存类型化列表。虽然将所有验证放在其构造函数中或附加类似函数非常好,但我无法使用智能感知,因为内部容器仍然只是一个标准数组。同样使用 get_class
似乎不太好,因为如果重命名 class 名称或命名空间,那么 IDE 重构功能不会选择此引用(好吧,PHPStorm 不会至少,我正在使用它)。
我当然不需要 intellisense,但这个 hack 的怪异让我想知道我是否有正确的方法来处理 PHP 中的 OOP,并认为我可能会遗漏一些东西。这是正确的做法还是我错过了什么?
如果您要走这条路,我会避免使用原生数组。我会让 classes 包含某种类型的数组。这样,您可以在 class 的构造函数中验证数组内容,然后您可以对对象使用实际类型提示,PHP 允许。
使用 phpstorm,当您添加注释时,它会正确地为您完成代码。
/**
* @param MyNamespace\MyObject[] $arrayOfObject
*/
function ProcessObjectArray(array $arrayOfObject)
{
foreach ($arrayOfObject as $key => $myObj) {
if (get_class($myObj) == 'MyNamespace\MyObject') {
if (false) $myObj = new MyObject();
// I can now access intellisense for MyObject in here
} else {
trigger_error('is not right object');
}
}
}
然而,智能感知不会阻止您传递不正确的对象,它只会帮助您在编码时防止传递不正确的对象。
也许您可能希望考虑使用集合而不是使用通用数组。
有很多示例,但这里有一个简单的示例,您可以对其进行扩展
class Collection
{
/** @var array */
private $items = [];
/**
* @param MyNamespace\MyObject $obj
* @return $this
*/
public function addItem(MyNamespace\MyObject $obj) {
$this->items[] = $obj;
return $this;
}
/**
* @param $index
* @return $this
*/
public function deleteItem($index) {
unset($this->items[$index]);
return $this;
}
/**
* @param $index
* @return MyNamespace\MyObject|null
*/
public function getItem($index) {
return array_key_exists($index, $this->items) ? $this->items[$index] : null;
}
/**
* @return MyNamespace\MyObject[]
*/
public function getItems() {
return $this->items;
}
/**
* @return int
*/
public function count() {
return sizeOf($this->items);
}
}
这是一个如何运作的例子:
$collection = new \Collection;
$obj = new MyNamespace\MyObject;
$collection->addItem($obj);
foreach($collection->getItems() as $item) {
// this will already know that $item is MyNamespace\MyObject because of the annotation on the getItems() method
$item->doSomething();
}
class MyCollection implements \Iterator
{
/**
* @var CollectionElement[]
*/
private $elements = [];
public function addElement(CollectionElement $element)
{
$this->elements[] = $element;
}
/**
* @return CollectionElement
*/
public function current()
{
return current($this->elements);
}
//... Rest of the Iterator implementation
}
这样您就无法向 collection 添加 CollectionElement
以外的任何内容。之后:
foreach($collection as $element){
/** @var CollectionElement $element */
$element->//here you will have autocompletion
}
您不需要检查任何内容,因为您的 collection 永远不会包含您不期望的任何内容。
我发现很多时候我将自定义对象数组传递给函数进行处理。在我的函数中,我在访问内部 properties/methods.
之前检查以确保它是正确的 class因为我正在使用一个数组,据我所知 PHP 没有任何类型化的通用列表,所以我不能使用类型提示,所以我的 IDE 中的智能感知不起作用并且代码检查抛出警告。
我遇到了一个旧的 post,它给出了加入这行代码的想法,以便在开发时让智能感知工作:
if (false) $myObj = new MyObject();
所以我最终得到了一个看起来像这样的函数:
function ProcessObjectArray(array $arrayOfObject)
{
foreach ($arrayOfObject as $key => $myObj) {
if (get_class($myObj) == 'MyNamespace\MyObject') {
if (false) $myObj = new MyObject();
// I can now access intellisense for MyObject in here
} else {
trigger_error('is not right object');
}
}
}
这似乎有点奇怪,所以我想知道这是否表明我没有以最佳方式处理对象数组,或者是否有更好的方式让我的智能感知工作。我查看了 arrayobject 接口,看看是否可以创建一个 class 实现 arrayobject 来保存类型化列表。虽然将所有验证放在其构造函数中或附加类似函数非常好,但我无法使用智能感知,因为内部容器仍然只是一个标准数组。同样使用 get_class
似乎不太好,因为如果重命名 class 名称或命名空间,那么 IDE 重构功能不会选择此引用(好吧,PHPStorm 不会至少,我正在使用它)。
我当然不需要 intellisense,但这个 hack 的怪异让我想知道我是否有正确的方法来处理 PHP 中的 OOP,并认为我可能会遗漏一些东西。这是正确的做法还是我错过了什么?
如果您要走这条路,我会避免使用原生数组。我会让 classes 包含某种类型的数组。这样,您可以在 class 的构造函数中验证数组内容,然后您可以对对象使用实际类型提示,PHP 允许。
使用 phpstorm,当您添加注释时,它会正确地为您完成代码。
/**
* @param MyNamespace\MyObject[] $arrayOfObject
*/
function ProcessObjectArray(array $arrayOfObject)
{
foreach ($arrayOfObject as $key => $myObj) {
if (get_class($myObj) == 'MyNamespace\MyObject') {
if (false) $myObj = new MyObject();
// I can now access intellisense for MyObject in here
} else {
trigger_error('is not right object');
}
}
}
然而,智能感知不会阻止您传递不正确的对象,它只会帮助您在编码时防止传递不正确的对象。
也许您可能希望考虑使用集合而不是使用通用数组。
有很多示例,但这里有一个简单的示例,您可以对其进行扩展
class Collection
{
/** @var array */
private $items = [];
/**
* @param MyNamespace\MyObject $obj
* @return $this
*/
public function addItem(MyNamespace\MyObject $obj) {
$this->items[] = $obj;
return $this;
}
/**
* @param $index
* @return $this
*/
public function deleteItem($index) {
unset($this->items[$index]);
return $this;
}
/**
* @param $index
* @return MyNamespace\MyObject|null
*/
public function getItem($index) {
return array_key_exists($index, $this->items) ? $this->items[$index] : null;
}
/**
* @return MyNamespace\MyObject[]
*/
public function getItems() {
return $this->items;
}
/**
* @return int
*/
public function count() {
return sizeOf($this->items);
}
}
这是一个如何运作的例子:
$collection = new \Collection;
$obj = new MyNamespace\MyObject;
$collection->addItem($obj);
foreach($collection->getItems() as $item) {
// this will already know that $item is MyNamespace\MyObject because of the annotation on the getItems() method
$item->doSomething();
}
class MyCollection implements \Iterator
{
/**
* @var CollectionElement[]
*/
private $elements = [];
public function addElement(CollectionElement $element)
{
$this->elements[] = $element;
}
/**
* @return CollectionElement
*/
public function current()
{
return current($this->elements);
}
//... Rest of the Iterator implementation
}
这样您就无法向 collection 添加 CollectionElement
以外的任何内容。之后:
foreach($collection as $element){
/** @var CollectionElement $element */
$element->//here you will have autocompletion
}
您不需要检查任何内容,因为您的 collection 永远不会包含您不期望的任何内容。