PHPDoc tipo de sugerencia para la matriz de objetos?


Por lo tanto, en PHPDoc se puede especificar @var por encima de la declaración de la variable miembro para indicar su tipo. Entonces un IDE, para ex. 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 pista adecuada cuando itere a través de esos objetos más adelante.

Entonces, ¿hay una manera de declarar una etiqueta PHPDoc para especificar que la variable miembro es una matriz de SomeObjs? @var array no es suficiente, y @var array(SomeObj) no parece ser válido, por ejemplo.

Author: Artem Russakovskii, 2009-04-22

13 answers

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->
}

Hago eso mucho en Zend Studio. No sé de otros editores, pero debería funcionar.

 273
Author: Zahymaka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-28 11:40:19

En el IDE 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 matriz. Solo se espera un tipo como elemento para un array dado.

Ejemplo: @return int[]

 863
Author: Nishi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-24 06:53:35

Netbeans sugerencias:

Se obtiene la finalización del código en $users[0]-> y para $this-> para una matriz de clases de usuario.

/**
 * @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->...

 55
Author: user1491819,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-02 11:47:23

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 de la foreach no es necesario.

 29
Author: Highmastdon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-01 13:16:13

PSR-5: PHPDoc propone una forma de notación genérica.

Sintaxis

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

Los valores en una Colección pueden incluso ser 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 un IDE para hacer asistencia de código, entonces es otra pregunta sobre si el IDE admite la notación de colecciones de estilo genérico PHPDoc.

De mi respuesta a esta pregunta.

 19
Author: Gerard Roche,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:55:07

Prefiero leer y escribir código limpio - como se describe en "Código limpio" por Robert C. Martin. Al seguir su credo, no debe requerir que el desarrollador (como usuario de su API) conozca la estructura (interna) de su matriz.

El usuario de la API puede preguntar: ¿Es una matriz con una sola dimensión? ¿Están los objetos repartidos en todos los niveles de una matriz multidimensional? Cuántos bucles anidados (foreach, etc.) ¿necesito acceder a todos los objetos? ¿Qué tipo de objetos se "almacenan" en ese matriz?

Como se ha descrito, desea usar esa matriz (que contiene objetos) como una matriz unidimensional.

Como lo describe Nishi, puede usar:

/**
 * @return SomeObj[]
 */

Para eso.

Pero de nuevo: tenga en cuenta - esto no es una notación docblock estándar. Esta notación fue introducida por algunos productores de IDE.

Vale, vale, como desarrollador sabes que "[] " está ligado a un array en PHP. Pero, ¿qué significa un "algo []" en un contexto PHP normal? "[] "significa: crear nuevo elemento dentro "algo". El nuevo elemento podría ser todo. Pero lo que desea expresar es: matriz de objetos con el mismo tipo y su tipo exacto. Como se puede ver, el productor 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 entender sus docblocks). Mal estilo!).

Debido a que su matriz tiene una dimensión, tal vez desee 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 mutch lo llamara "colección", por ejemplo.

Recuerde: usted 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 atravesable como una matriz. Por ejemplo:

class orderCollection implements ArrayIterator

O si desea almacenar los objetos internos en diferentes niveles dentro de una matriz multidimensional/estructura de objetos:

class orderCollection implements RecursiveArrayIterator

Esta solución reemplaza su matriz por un objeto de tipo "orderCollection", pero no habilite la finalización de código dentro de su IDE hasta ahora. Vale. Siguiente paso:

Implementa los métodos que introduce la interfaz con docblocks-particular:

/**
 * [...]
 * @return Order
 */
orderCollection::current()

/**
 * [...]
 * @return integer E.g. database identifier of the order
 */
orderCollection::key()

/**
 * [...]
 * @return Order
 */
orderCollection::offsetGet()

No se olvide de usar la sugerencia de tipo para:

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

Esta solución deja de introducir una gran cantidad de:

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

En todos sus archivos de código (por ejemplo, dentro de bucles), como Zahymaka confirmó con su respuesta. Su usuario de la API no está obligado a introducir que docblocks, para tener la finalización de código. Tener @ retorno en solo uno place reduce la redundancia (@var) lo más mutch posible. Rociar "docBlocks con @ var" haría que su código sea peor legible.

Finalmente has terminado. Parece difícil de conseguir? Parece tomar un martillo para romper una nuez? 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 / lee muchas.

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 bien, envíe una solicitud de característica en el gestor de incidencias de su productor IDE.

Gracias a Christian Weiss (de Alemania) por ser mi entrenador y por enseñarme cosas tan buenas. PS: Nos vemos a él y a mí en XING.

 12
Author: DanielaWaranie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-01 20:27:26

Como mencionó DanielaWaranie en su respuesta, hay una manera de especificar el tipo de item item cuando itera sobre items items en coll collectionObject: Agregue @return MyEntitiesClassName a current() y el resto de los métodos Iterator y ArrayAccess que devuelven valores.

Boom! No hay necesidad en /** @var SomeObj[] $collectionObj */ sobre foreach, y funciona bien con el objeto de colección, no hay necesidad de devolver la colección con el método específico descrito como @return SomeObj[].

Sospecho que no todos los IDE lo soportan, pero funciona perfectamente bien en PhpStorm, lo que hace que yo 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
}

Lo útil que iba a agregar al publicar esta respuesta

En mi caso current() y el resto de interface-los métodos se implementan en la clase Abstract-collection y no sé qué tipo de entidades se almacenarán eventualmente en collection.

Así que aquí está el truco: No especifique el tipo de retorno en la clase abstracta, en su lugar use la instucción de PHPDoc @method en la descripción de la colección específica clase.

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 soportan, pero PhpStorm sí. Pruebe el suyo, publicar en comentario los resultados!

 5
Author: Pavel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-30 04:28:22

En NetBeans 7.0 (puede ser inferior también) puede declarar el tipo devuelto "array with Text objects" igual que @return Text y la sugerencia de código funcionará:

Editar: actualizado el ejemplo con la sugerencia @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", bruja no trae ningún valor.

CONTRAS es que se le permite pisar la matriz como Objeto de texto que arrojará errores.

 4
Author: d.raev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-09-20 07:12:01

Utilice array[type] en Zend Studio.

En Zend Studio, array[MyClass] o array[int] o incluso array[array[MyClass]] funcionan muy bien.

 4
Author: Erick Robertson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-14 23:18:31

El problema es que @var puede simplemente denotar un solo tipo - No contener una fórmula compleja. Si tenía una sintaxis para "array of Foo", ¿por qué detenerse allí y no agregar una sintaxis para"array of array, que contiene 2 Foo y tres compases"? Entiendo que una lista de elementos es quizás más genérica que eso, pero es una pendiente resbaladiza.

Personalmente, algunas veces he usado @var Foo[] para significar "una matriz de Foo", pero no es compatible con IDE.

 2
Author: troelskn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-04-22 21:04:10
<?php foreach($this->models as /** @var Model_Object_WheelModel */ $model): ?>
    <?php
    // Type hinting now works:
    $model->getImage();
    ?>
<?php endforeach; ?>
 1
Author: Scott Hovestadt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-27 21:29:11

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, es no la mejor manera de hacerlo. No en PhpStorm al menos, aunque no he probado NetBeans.

La mejor manera consiste en extender la clase ArrayIterator en lugar de usar tipos de array nativos. Esto le permite escribir una pista a nivel de clase en lugar de a nivel de instancia, lo que significa que solo tiene que PHPDoc una vez, no a lo largo de su código (que no solo es desordenado y viola SECO, pero también puede ser problemático cuando se trata de refactorización - PhpStorm tiene la costumbre de perder PHPDoc cuando refactorización)

Véase el código siguiente:

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();

La clave aquí es el PHPDoc @method MyObj current() sobreescribiendo 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 la finalización del código cuando nos referimos a la variable $myObj->...

Para mí, esta es la mejor manera de lograr esto (al menos hasta que PHP introduzca Arrays tipeados, si es que alguna vez lo hacen), ya que estamos declarando el tipo iterador en la clase iterable, no en instancias de la clase dispersas por todo el código.

No he mostrado aquí la solución completa para extender ArrayIterator, por lo que si usa esta técnica, también puede querer:

  • Incluya otros PHPDoc a nivel de clase según sea necesario, para métodos como offsetGet($index) y next()
  • Mueva el sanity check is_a($object, MyObj::class) del constructor a un método privado
  • Llame a este (ahora privado) sanity check desde anulaciones de métodos como offsetSet($index, $newval) y append($value)
 1
Author: e_i_pi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-23 00:21:18

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();
}
 -5
Author: eupho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-13 10:43:15