phpdocumentor - phpdoc example
PHPDoc tipo de sugerencias para la matriz de objetos? (13)
Por lo tanto, en PHPDoc, se puede especificar @var
encima de la declaración de la variable miembro para indicar su tipo. Luego un IDE, por ej. PHPEd, sabrá con qué tipo de objeto está trabajando y será capaz de proporcionar una visión de código para esa variable.
<?php
class Test
{
/** @var SomeObj */
private $someObjInstance;
}
?>
Esto funciona muy bien hasta que necesito hacer lo mismo con una matriz de objetos para poder obtener una sugerencia adecuada cuando repito esos objetos más adelante.
Entonces, ¿hay una manera de declarar una etiqueta PHPDoc para especificar que la variable miembro es una matriz de SomeObj
s? @var
matriz @var
no es suficiente, y la @var array(SomeObj)
no parece ser válida, por ejemplo.
Como mencionó DanielaWaranie en su respuesta, hay una manera de especificar el tipo de $ item cuando se iteran más de $ items en $ collectionObject: Agregue @return MyEntitiesClassName
a current()
y el resto de ArrayAccess
y ArrayAccess
que devuelven valores.
¡Auge! No es necesario en /** @var SomeObj[] $collectionObj */
over foreach
, y funciona correctamente con el objeto de colección, no es necesario devolver la colección con un método específico descrito como @return SomeObj[]
.
Sospecho que no todos los IDE lo admiten, pero funciona perfectamente bien en PhpStorm, lo que me hace más feliz.
Ejemplo:
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
}
¿Qué utilidad iba a agregar publicando esta respuesta?
En mi caso current()
y el resto de los métodos de interface
se implementan en la clase de colección Abstract
y no sé qué tipo de entidades se almacenarán finalmente en la colección.
Así que aquí está el truco: no especifique el tipo de retorno en la clase abstracta, en su lugar use PhpDoc instuction @method
en la descripción de la clase de colección específica.
Ejemplo:
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...
}
Ahora, uso de clases:
$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();
}
Una vez más: sospecho que no todos los IDE lo admiten, pero PhpStorm sí. Prueba el tuyo, publica en el comentario los resultados!
Consejos Netbeans:
Obtiene la finalización del código en $users[0]->
y por $this->
para una variedad de clases de User.
/**
* @var User[]
*/
var $users = array();
También puede ver el tipo de la matriz en una lista de miembros de la clase cuando complete $this->...
El problema es que @var
solo puede denotar un solo tipo - No contiene una fórmula compleja. Si tenía una sintaxis para "matriz de Foo", ¿por qué detenerse allí y no agregar una sintaxis para "matriz de matriz, que contiene 2 Foo y tres barras"? Entiendo que una lista de elementos es quizás más genérica que eso, pero es una pendiente resbaladiza.
Personalmente, algunas veces @var Foo[]
usado @var Foo[]
para indicar "una matriz de Foo''s", pero no es compatible con IDE.
En NetBeans 7.0 (también puede ser más bajo), puede declarar el tipo de devolución "matriz con objetos de texto" tal como @return Text
y la sugerencia de código funcionarán:
Editar: actualizado el ejemplo con la sugerencia de @Bob Fanger
/**
* get all Tests
*
* @return Test|Array $tests
*/
public function getAllTexts(){
return array(new Test(), new Test());
}
y solo úsalo
$tests = $controller->getAllTests();
//$tests-> //codehinting works!
//$tests[0]-> //codehinting works!
foreach($tests as $text){
//$test-> //codehinting works!
}
No es perfecto, pero es mejor dejarlo solo "mezclado", lo que no aporta ningún valor.
CONS es que se le permite recorrer la matriz como objeto de texto que arrojará errores.
En el IDE de PhpStorm de JetBrains, puede usar /** @var SomeObj[] */
, por ejemplo:
/**
* @return SomeObj[]
*/
function getSomeObjects() {...}
La documentación de phpdoc recomienda este método:
especificado que contiene un solo tipo, la definición de Tipo informa al lector del tipo de cada elemento de la matriz. Solo se espera un tipo como elemento para una matriz dada.
Ejemplo:
@return int[]
He encontrado algo que está funcionando, puede salvar vidas!
private $userList = array();
$userList = User::fetchAll(); // now $userList is an array of User objects
foreach ($userList as $user) {
$user instanceof User;
echo $user->getName();
}
Para especificar una variable es una matriz de objetos:
$needles = getAllNeedles();
/* @var $needles Needle[] */
$needles[1]->... //codehinting works
Esto funciona en Netbeans 7.2 (lo estoy usando)
Funciona también con:
$needles = getAllNeedles();
/* @var $needles Needle[] */
foreach ($needles as $needle) {
$needle->... //codehinting works
}
Por lo tanto, el uso de la declaración dentro del foreach
no es necesario.
Prefiero leer y escribir código limpio, como se describe en "Código limpio" por Robert C. Martin. Al seguir su credo, no debe exigir al desarrollador (como usuario de su API) que conozca la estructura (interna) de su matriz.
El usuario de la API puede preguntar: ¿Es eso una matriz con una sola dimensión? ¿Los objetos se reparten en todos los niveles de una matriz multidimensional? ¿Cuántos bucles anidados (foreach, etc.) necesito para acceder a todos los objetos? ¿Qué tipo de objetos se "almacenan" en esa matriz?
Como lo describió, desea usar esa matriz (que contiene objetos) como una matriz unidimensional.
Como lo indica Nishi, puede usar:
/**
* @return SomeObj[]
*/
para eso.
Pero nuevamente: tenga en cuenta que esta no es una notación estándar de bloque de documentos. Esta notación fue introducida por algunos productores de IDE.
Bien, bien, como desarrollador, sabes que "[]" está vinculado a una matriz en PHP. Pero, ¿qué significa "algo []" en el contexto normal de PHP? "[]" significa: crear un elemento nuevo dentro de "algo". El nuevo elemento podría ser todo. Pero lo que quiere expresar es: matriz de objetos con el mismo tipo y su tipo exacto. Como puede ver, el productor de IDE introduce un nuevo contexto. Un nuevo contexto que tenías que aprender. Un nuevo contexto que otros desarrolladores de PHP tuvieron que aprender (para comprender sus docblocks). Mal estilo (!).
Debido a que su matriz tiene una dimensión, tal vez quiera llamar a esa "matriz de objetos" una "lista". Tenga en cuenta que "lista" tiene un significado muy especial en otros lenguajes de programación. Sería mejor que llamarlo "colección", por ejemplo.
Recuerde: utiliza un lenguaje de programación que le permite todas las opciones de OOP. Use una clase en lugar de una matriz y haga que su clase sea transitable como una matriz. P.ej:
class orderCollection implements ArrayIterator
O si desea almacenar los objetos internos en diferentes niveles dentro de una estructura de matriz / objeto multidimensional:
class orderCollection implements RecursiveArrayIterator
Esta solución reemplaza su matriz por un objeto de tipo "orderCollection", pero no permite la finalización de código dentro de su IDE hasta ahora. Bueno. Próximo paso:
Implemente los métodos introducidos por la interfaz con docblocks, en particular:
/**
* [...]
* @return Order
*/
orderCollection::current()
/**
* [...]
* @return integer E.g. database identifier of the order
*/
orderCollection::key()
/**
* [...]
* @return Order
*/
orderCollection::offsetGet()
No te olvides de utilizar sugerencias de tipo para:
orderCollection::append(Order $order)
orderCollection::offsetSet(Order $order)
Esta solución deja de introducir un montón de:
/** @var $key ... */
/** @var $value ... */
en todos sus archivos de código (por ejemplo, dentro de los bucles), como confirmó Zahymaka con su respuesta. El usuario de la API no está obligado a introducir los bloques de documentos para completar el código. Tener @return en un solo lugar reduce la redundancia (@var) lo más posible. Espolvorear "docBlocks with @var" haría que su código sea lo más legible posible.
Finalmente has terminado. Parece difícil de alcanzar? Parece que tomar un martillo para romper una tuerca? No realmente, ya que estás familiarizado con esas interfaces y con el código limpio. Recuerde: su código fuente se escribe una vez / lea muchos.
Si la finalización del código de su IDE no funciona con este enfoque, cambie a uno mejor (por ejemplo, IntelliJ IDEA, PhpStorm, Netbeans) o presente una solicitud de función en el rastreador de problemas de su productor de IDE.
Gracias a Christian Weiss (de Alemania) por ser mi entrenador y por enseñarme cosas tan maravillosas. PD: Encuéntrame y lo encuentro en XING.
Sé que llego tarde a la fiesta, pero he estado trabajando en este problema recientemente. Espero que alguien vea esto porque la respuesta aceptada, aunque correcta, no es la mejor manera de hacerlo. Al menos no en PHPStorm, aunque no he probado NetBeans.
La mejor manera es extender la clase ArrayIterator en lugar de usar tipos de arreglos nativos. Esto le permite escribir una sugerencia a nivel de clase en lugar de a nivel de instancia, lo que significa que solo tiene que usar PHPDoc una vez, no a través de su código (que no solo es desordenado y viola DRY, sino que también puede ser problemático cuando se trata de refactorización - PHPStorm tiene el hábito de perder PHPDoc cuando refactoriza)
Ver código a continuación:
<?php foreach($this->models as /** @var Model_Object_WheelModel */ $model): ?>
<?php
// Type hinting now works:
$model->getImage();
?>
<?php endforeach; ?>
La clave aquí es el PHPDoc @method MyObj current()
reemplaza el tipo de retorno heredado de ArrayIterator (que es mixed
). La inclusión de este PHPDoc significa que cuando iteramos sobre las propiedades de la clase usando foreach($this as $myObj)
, obtenemos el código completo al referirnos a la variable $myObj->...
Para mí, esta es la mejor manera de lograr esto (al menos hasta que PHP introduzca Matrices mecanografiadas, si es que alguna vez lo hacen), ya que estamos declarando el tipo de iterador en la clase iterable, no en instancias de la clase dispersas en todo el código.
No he mostrado aquí la solución completa para extender ArrayIterator, por lo que si utiliza esta técnica, es posible que también desee:
- Incluya otros PHPDoc de nivel de clase según sea necesario, para métodos como
offsetGet($index)
ynext()
- Mueva la verificación de
is_a($object, MyObj::class)
del constructor a un método privado - Llame a esta comprobación de
offsetSet($index, $newval)
(ahora privada) de losoffsetSet($index, $newval)
de método comooffsetSet($index, $newval)
yappend($value)
PSR-5: PHPDoc propone una forma de notación de estilo genérico.
Sintaxis
Type[]
Type<Type>
Type<Type[, Type]...>
Type<Type[|Type]...>
Los valores en una Colección PUEDEN ser incluso otra matriz e incluso otra Colección.
Type<Type<Type>>
Type<Type<Type[, Type]...>>
Type<Type<Type[|Type]...>>
Ejemplos
<?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> */
Nota: si está esperando que un IDE realice la asistencia de código, entonces es otra pregunta sobre si el IDE admite la notación de colecciones de estilo genérico de PHPDoc.
De mi respuesta a esta pregunta .
Use array[type]
en Zend Studio.
En Zend Studio, array[MyClass]
o array[int]
o incluso array[array[MyClass]]
funcionan muy bien.
Utilizar:
/* @var $objs Test[] */
foreach ($objs as $obj) {
// Typehinting will occur after typing $obj->
}
al tipear las variables en línea, y
class A {
/** @var Test[] */
private $items;
}
para propiedades de clase.
Respuesta anterior de ''09 cuando PHPDoc (e IDE como Zend Studio y Netbeans) no tenían esa opción:
Lo mejor que puedes hacer es decir,
foreach ($Objs as $Obj)
{
/* @var $Obj Test */
// You should be able to get hinting after the preceding line if you type $Obj->
}
Lo hago mucho en Zend Studio. No sé sobre otros editores, pero debería funcionar.
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();