tag name get_the_tags first all php arrays type-hinting

php - name - get_the_tags wp



Indicación de tipo: especifique una matriz de objetos (5)

Las funciones antiguas, pero variadas y el desempaquetado de matrices se pueden usar (con algunas limitaciones) para cumplir con las sugerencias de matrices escritas, al menos con PHP7. (No probé en versiones anteriores).

Ejemplo:

class Foo { public function test(){ echo "foo"; } }; class Bar extends Foo { //override parent method public function test(){ echo "bar"; } } function test(Foo ...$params){ foreach($params as $param){ $param->test(); } } $f = new Foo(); $b = new Bar(); $arrayOfFoo = [$f,$b]; test(...$arrayOfFoo); //will output "foobar"


Las limitaciones:

  1. Esto no es técnicamente una solución, ya que en realidad no estás pasando una matriz escrita. En su lugar, utiliza el operador de desempaquetado de arreglos 1 (el "..." en la llamada a la función) para convertir su arreglo en una lista de parámetros, cada uno de los cuales debe ser del tipo indicado en la declaración variadic 2 (que también emplea un elipsis).

  2. El "..." en la llamada de función es absolutamente necesario (lo que no es sorprendente, dado lo anterior). Tratando de llamar

    test($arrayOfFoo)

    en el contexto del ejemplo anterior se producirá un error de tipo, ya que el compilador espera parámetros (es) de foo, no una matriz. Vea a continuación una solución, aunque novedosa, para pasar directamente a una matriz de un tipo dado, al tiempo que se conservan algunas sugerencias de tipo.

  3. Las funciones Variadic pueden tener solo un parámetro variadic y debe ser el último parámetro (ya que, de lo contrario, el compilador podría determinar dónde termina el parámetro variadic y comienza el siguiente), lo que significa que no podría declarar funciones a lo largo de las líneas de

    function test(Foo ...$foos, Bar ...$bars){ //... }

    o

    function test(Foo ...$foos, Bar $bar){ //... }


Una alternativa solo un poco mejor que una simple comprobación de cada elemento:

El siguiente procedimiento es mejor que simplemente verificar el tipo de cada elemento en la medida en que (1) garantiza que los parámetros utilizados en el cuerpo funcional son del tipo correcto sin saturar la función con verificaciones de tipo, y (2) arroja las excepciones de tipo habituales .

Considerar:

function alt(Array $foos){ return (function(Foo ...$fooParams){ //treat as regular function body foreach($fooParams as $foo){ $foo->test(); } })(...$foos); }

La idea es definir y devolver el resultado de un cierre invocado de inmediato que se encargue de todos los negocios variados / de desempaque para usted. (Se podría extender el principio aún más, definiendo una función de orden superior que genere funciones de esta estructura, reduciendo el estándar). En el ejemplo anterior:

alt($arrayOfFoo) // also outputs "foobar"

Los problemas con este enfoque incluyen:

(1) Especialmente para desarrolladores inexpertos, puede ser poco claro.

(2) Puede incurrir en una sobrecarga de rendimiento.

(3) Al igual que simplemente verifica internamente los elementos de la matriz, trata la verificación de tipo como un detalle de implementación, en la medida en que uno debe inspeccionar la declaración de función (o disfrutar de excepciones de tipo) para darse cuenta de que solo una matriz específicamente escrita es un parámetro válido. En una interfaz o función abstracta, la sugerencia de tipo completo no se pudo codificar; todo lo que uno podría hacer es comentar que se espera una implementación del orden anterior (o algo similar).


Notas

[1]. En pocas palabras: el desempaquetado de matrices es equivalente

example_function($a,$b,$c);

y

example_function(...[$a,$b,$c]);


[2]. En pocas palabras: variad funciones de la forma

function example_function(Foo ...$bar){ //... }

puede ser invocado válidamente de cualquiera de las siguientes maneras:

example_function(); example_function(new Foo()); example_function(new Foo(), new Foo()); example_function(new Foo(), new Foo(), new Foo()); //and so on

¿Cómo puedo especificar el tipo de argumento como una matriz? Digamos que tengo una clase llamada ''Foo'':

class Foo {}

y luego tengo una función que acepta ese tipo de clase como un argumento:

function getFoo(Foo $f) {}

Cuando paso una serie de ''Foo''s, aparece un error:

Error fatal detectable : el argumento 1 pasado a getFoo () debe ser una instancia de Foo, dado el array

¿Hay alguna manera de superar este problema? tal vez algo como

function getFoo(Foo $f[]) {}


Lo sentimos, PHP no funciona de esta manera. Se ha diseñado para la programación rápida y sencilla, por lo que no le molestan los teclados estrictos, lo que lo deja en el infierno de tipo dinámico sin ayuda (como un compilador de inferencias de tipo). El intérprete de PHP no tiene ni idea de lo que has puesto en tu matriz, por lo que debe iterar sobre todas las entradas de la matriz si quiere validar algo como

function bar(Foo[] $myFoos)

Este es un gran impacto en el rendimiento cuando la matriz se hace grande. Creo que esa es la razón por la que PHP no ofrece sugerencias de matrices escritas.

Las otras respuestas aquí sugieren que cree su envoltorio de matriz fuertemente tipado. Los envoltorios están bien cuando tienes un compilador con escritura genérica como Java o C #, pero para PHP, no estoy de acuerdo. Aquí, esos envoltorios son tediosos códigos repetitivos y debes crear uno para cada arreglo escrito. Si desea utilizar funciones de matriz de la biblioteca, necesita ampliar sus envoltorios con funciones de delegación de comprobación de tipos y ampliar su código. Esto se puede hacer en una muestra académica, pero en un sistema de producción con muchas clases y colecciones, donde el tiempo del desarrollador es costoso y los MIPS en el clúster web son escasos. Yo creo que no.

Por lo tanto, solo para tener una validación de tipo PHP en la firma de función, me abstendré de envoltorios de matrices fuertemente tipados. No creo que te den un ROI suficiente. La compatibilidad con PHPDoc de las buenas IDE de PHP lo ayuda más, y en las etiquetas PHPDoc, la notación Foo [] funciona.

Por otro lado, los envoltorios PUEDEN tener sentido si puedes concentrar una buena lógica de negocios en ellos.

Quizás llegue el día en que PHP se extienda con arreglos fuertemente tipados (o más precisos: diccionarios fuertemente tipados). Me gustaria eso. Y con ellos, pueden proporcionar sugerencias de firma que no te castigan.


Si desea asegurarse de que está trabajando con "Array of Foo" y desea asegurarse de que los métodos reciban "Array of Foo", puede:

class ArrayOfFoo extends /ArrayObject { public function offsetSet($key, $val) { if ($val instanceof Foo) { return parent::offsetSet($key, $val); } throw new /InvalidArgumentException(''Value must be a Foo''); } }

entonces:

function workWithFoo(ArrayOfFoo $foos) { foreach ($foos as $foo) { // etc. } } $foos = new ArrayOfFoos(); $foos[] = new Foo(); workWithFoo($foos);

La salsa secreta es que estás definiendo un nuevo "tipo" de "array of foo", y luego pasas ese "tipo" usando una protección de tipo insinuación.

La biblioteca de Haldayne maneja la placa de repetición para las verificaciones de los requisitos de membresía si no desea hacer su propio rollo:

class ArrayOfFoo extends /Haldayne/Boost/MapOfObjects { protected function allowed($value) { return $value instanceof Foo; } }

(Revelación completa, soy el autor de Haldayne.)

Nota histórica: el Array Of RFC propuso esta característica en 2014. El RFC se rechazó con 4 yay y 16 no. El concepto reapareció recientemente en la lista interna , pero las quejas han sido muy similares a las del RFC original: agregar esta verificación afectaría significativamente el rendimiento .


class Foo { /** * @param Foo[] $f */ function getFoo($f) { } }


function getFoo()

En general, entonces tendrías un método de adición que escribiría una sugerencia a Foo

function addFoo( Foo $f )

Por lo tanto, el getter devolvería una matriz de Foo''s y el método add puede asegurar que solo tengas Foo''s en la matriz.

EDITAR Eliminado el argumento del getter. No sé lo que estaba pensando, no necesitas una discusión en un getter.

EDITAR solo para mostrar el ejemplo de una clase completa:

class FooBar { /** * @return array */ private $foo; public function getFoo() { return $foo; } public function setFoo( array $f ) { $this->foo = $f; return $this; } public function addFoo( Foo $f ) { $this->foo[] = $f; return $this; } }

Por lo general, y probablemente no debería, tiene el método de establecimiento, ya que tiene el método de adición para ayudar a garantizar que $foo sea ​​una matriz de Foo , pero ayuda a ilustrar lo que está sucediendo en la clase.