2012-04-17 7 views
10

Me gusta crear mis funciones de PHP usando key => value pairs (arrays) como argumentos en lugar de parámetros individuales.Argumentos de función PHP: ¿usar una matriz o no?

Por ejemplo, yo prefiero:

function useless_func($params) { 
    if (!isset($params['text'])) { $params['text'] = "default text"; }  
    if (!isset($params['text2'])) { $params['text2'] = "default text2"; } 
    if (!isset($params['text3'])) { $params['text3'] = "default text3"; } 
    echo $params['text'].$params['text2'].$params['text3']; 
    return; 
} 

Y que no me gustan:

function useless_func($text = "default text", $text2 = "default text2", $text3 = "default text3") { 
     echo $text.$text2.$text3; 
    return; 
} 

que había visto primero las cosas de esta manera extensa en el código base de Wordpress.

La razón por la que prefiero matrices:

  • Parámetros de las funciones se pueden proporcionar en cualquier orden
  • más fácil de leer código/más autodocumentado (en mi opinión)
  • menos propenso a errores, porque cuando llamando a una función, debo investigar las teclas adecuadas del arreglo

Estaba hablando de esto con un compañero de trabajo y él dice que es inútil y solo lleva a código adicional y es mucho más difícil para establecer los valores predeterminados. Básicamente, él no está de acuerdo conmigo completamente en los tres puntos.

Estoy buscando algunos consejos generales y orientación de expertos que puedan proporcionar información: ¿Cuál es la forma mejor o más adecuada para hacer esto?

+0

No entiendo por qué las personas en su mayoría no lo pasan de la manera que usted ha mencionado. Creo que es una manera flexible, incluso si alguien está trabajando en su función. Estoy desarrollando un marco que requiere raw_queries, y algunos más cosas. Y la capacidad de analizar una matriz de parámetros lo hace muy flexible. – DaAmidza

Respuesta

15

Bueno, es un poco útil. Pero para algunos argumentos que están pasando siempre es mejor usar un pase clásico como function some($a1, $a2). Que estoy haciendo como esto en mi código:

function getSome(SomeClass $object, array $options = array()) 
{ 
    // $object is required to be an instance of SomeClass, and there's no need to get element by key, then check if it's an object and it's an instance of SomeClass 

    // Set defaults for all passed options 
    $options = array_merge(array(
     'property1' => 'default1', 
     'property2' => 'default2', 
     ... => ... 
    ), $options); 
} 

Por lo tanto, como se puede ver me gusta ese estilo de código también, pero para los principales argumentos prefiero estilo clásico, porque de esa manera PHP controla más cosas que debería hacerlo , si utilicé el estilo del código.

+0

Los argumentos del "núcleo" son subjetivos y pueden conducir a una lista de args de Navidad. Si sigues la regla dura y rápida de más de 2, debería ser una matriz, independientemente de si es central o no. –

0

Su compañero de trabajo está loco. Es perfectamente aceptable pasar una matriz como un argumento de función. Es frecuente en muchas aplicaciones de código abierto, incluidas Symfony y Doctrine. Siempre he seguido la regla de 2 argumentos, si una función necesita más de dos argumentos, O si cree que usará más de dos argumentos en el futuro, use una matriz. IMO esto permite la mayor flexibilidad y reduce cualquier defecto de código de llamada que pueda surgir si un argumento se pasa incorrectamente.

Claro que se necesita un poco más de trabajo para extrapolar los valores de la matriz, y debe tener en cuenta los elementos necesarios, pero hace que agregar características sea mucho más fácil, y es mucho mejor que pasar 13 argumentos a la función cada vez que necesita ser llamado.

Aquí es un fragmento de código que muestra la requerida vs parametros opcionales sólo para darles una idea:

// Class will tokenize a string based on params 
public static function tokenize(array $params) 
{ 
    // Validate required elements 
    if (!array_key_exists('value', $params)) { 
     throw new Exception(sprintf('Invalid $value: %s', serialize($params))); 
    }   

    // Localize optional elements 
    $value   = $params['value']; 
    $separator  = (array_key_exists('separator', $params)) ? $params['separator'] : '-'; 
    $urlEncode  = (array_key_exists('urlEncode', $params)) ? $params['urlEncode'] : false; 
    $allowedChars  = (array_key_exists('allowedChars', $params)) ? $params['allowedChars'] : array(); 
    $charsToRemove = (array_key_exists('charsToRemove', $params)) ? $params['charsToRemove'] : array(); 

.... 
5

Su compañero de trabajo que es correcto. No solo es más código para la misma funcionalidad, es más difícil de leer y probablemente ha reducido el rendimiento (ya que necesita llamar al isset para cada parámetro y necesita acceder a una matriz para establecer los valores).

+0

¿Has visto @devdRew arriba, dirías que la función array_merge() aún retendrá el agua para "más lento"? – ethanpil

+0

Eso es una especie de "guerra acechada", usar o no usar argumentos agregados en matriz, pero si dice que es más sencillo usar argumentos separados, por ejemplo, para almacenar algún registro en la base de datos con valores pasados, no lo hace usar para cada valor de fila como un argumento separado. ¿Derecha? – devdRew

9

Estoy asumiendo que estás preguntando si es una buena cosa escribir todos funciones para que acepten sólo un argumento, y para ese argumento debe ser una matriz?

Si usted es la única persona que alguna vez va a trabajar en su código, entonces puede hacer lo que quiera. Sin embargo, al pasar todos los valores de argumento a través de una matriz, cualquier otra persona tendrá que trabajar más para comprender qué hace la función y por qué y cómo podrían usarla, especialmente si están usando un IDE con autocompletado para nombres de funciones. etc. No lo llaman una "firma de función" por nada.

Recomendaría que los parámetros de la matriz estén reservados para los elementos donde no se sabe cuántos (por ejemplo, una serie de elementos de datos), o para grupos de opciones/configuraciones relacionadas (que pueden ser lo que está sucediendo) en el ejemplo de Wordpress que mencionas?).

Si continúa con un enfoque general de los argumentos de matriz, al menos debe ser consciente de su impacto en la legibilidad y tomar algunas medidas para contrarrestar ese problema.

+0

Creo que la documentación adecuada puede servir como un "paso para contrarrestar ese problema" muy válido. – ethanpil

+0

Escucho lo que dice, pero si su código está bien escrito, en su mayoría debe ser autodocumentado, en cuyo caso no necesita 'documentarlo' (por ejemplo, con comentarios, etc.). Esto también resuelve problemas que pueden surgir cuando el código no se sincroniza con la 'documentación'. – Squig

4

Esto limita al Cargo Cult programming. Usted dice que esto es más legible y autodocumentado. Yo preguntaría ¿cómo? Para saber cómo usar su función/método, tengo que leer el código en sí. No hay forma de que sepa cómo usarlo desde la firma en sí. Si usa cualquier IDE o editor medianamente decente que admita sugerencias de firma de método, este será un PITA real. Además, no podrá usar la sintaxis de sugerencias de tipo de PHP.

Si encuentra que está codificando una carga de parámetros, especialmente parámetros opcionales, entonces sugiere que puede haber algún problema con su diseño. Considera cómo más puedes hacerlo. Si algunos o todos los parámetros están relacionados, entonces tal vez pertenecen a su propia clase.

4

El uso de array_merge() funciona bien, pero también se puede usar el operador +; funciona de otra manera, solo agrega valores predeterminados donde aún no se ha otorgado uno.

function useless_func(array $params = array()) 
{ 
    $params += array(
     'text' => 'default text', 
     'text2' => 'default text2', 
     'text3' => 'default text3', 
    ); 
} 

Consulte también: Function Passing array to defined key

algunas cosas que no se consigue con la utilización de matrices como argumentos de la función es:

  1. tipo de cheques (sólo aplicable a los objetos y las matrices, pero puede ser útil y en algunos casos esperado).
  2. Los editores de texto inteligentes (er) tienen una función de visión del código que mostrará los argumentos que comprende una función; el uso de matrices elimina esa característica, aunque podría agregar las posibles claves en la función docblock.
  3. debido al n. ° 2, en realidad se vuelve más propenso a errores, ya que puede escribir mal la clave del arreglo.
0

@ Mike, que también podría "extraer()" de su argumento $ params en variables locales, así:

// Class will tokenize a string based on params 
public static function tokenize(array $params) 
{ 
    extract($params); 
    // Validate required elements 
    if (!isset($value)) { 
     throw new Exception(sprintf('Invalid $value: %s', serialize($params))); 
    } 

    // Localize optional elements 
    $value   = isset($value) ? $value : ''; 
    $separator  = isset($separator) ? $separator] : '-'; 
    $urlEncode  = isset($urlEncode) ? $urlEncode : false; 
    $allowedChars = isset($allowedChars) ? $allowedChars : array(); 
    $charsToRemove = isset($charsToRemove) ? $charsToRemove : array(); 

....

misma implementación, pero más corto.

0

He usado matrices para sustituir una larga lista de parámetros en muchas ocasiones y ha funcionado bien.Estoy de acuerdo con aquellos en esta publicación que han mencionado que los editores de código no pueden dar pistas sobre los argumentos. El problema es que si tengo 10 argumentos, y los primeros 9 son en blanco/nulo, se vuelve difícil de manejar cuando se llama a esa función.

También me gustaría escuchar cómo rediseñar una función que requiere muchos argumentos. Por ejemplo, cuando tenemos una función que genera las sentencias SQL sobre la base de ciertos argumentos que establecer:

function ($a1, $a2, ... $a10){ 

     if($a1 == "Y"){$clause_1 = " something = ".$a1." AND ";} 
     ... 
     if($a10 == "Y"){$clause_10 = " something_else = ".$a10." AND ";} 

     $sql = " 
     SELECT * FROM some_table 
     WHERE 
     ".$clause_1." 
     .... 
     ".$clause_10." 
     some_column = 'N' 
     "; 

     return $sql; 
    } 

me gustaría ver entretener PHP añadiendo una función de ayuda nativa que podría ser utilizado dentro de una la función que se llama que lo haría ayudar a pasar una serie de parámetros emprendiendo la verificación de tipos necesaria. PHP reconoció esto hasta cierto punto al crear la función func_get_args() que permite que los argumentos se pasen en cualquier orden. PERO esto solo pasará una COPIA de los valores, por lo que si desea pasar objetos a la función, esto será un problema. Si tal función existiera, los editores del código podrían recoger esto y proporcionar detalles sobre posibles argumentos.

+0

Si la función tiene 10 argumentos, es más que probable que esté mal diseñada y deba ser repensada. –

11

¡No hagas eso!

Pasar todo en una matriz es una mala idea la mayor parte del tiempo.

  • Impide que las personas utilicen su función sin saber lo que necesita para funcionar.
  • Te permite crear funciones que necesitan una gran cantidad de parámetros cuando, probablemente, se debe crear una función con las necesidades de los argumentos más precisos y un objetivo más estrecho

Parece que al contrario de injecting en una función de lo que necesita.

Parámetros de las funciones se pueden proporcionar en cualquier orden

que no tengo esa preferencia. No entiendo esa necesidad.

más fácil de leer código/más autodocumentado (en mi opinión)

La mayoría de los entornos de desarrollo le presentarán los diferentes argumentos necesita una función. Si uno ve una declaración de función como foo(Someclass $class, array $params, $id), está muy claro qué necesita la función. No estoy de acuerdo en que un solo argumento de param sea más fácil de leer o auto documentar.

menos propenso a errores, porque cuando se llama a una función que debo investigar las claves de matriz adecuados

Permitir que la gente pase en una matriz sin saber que los valores serán impago no esté cerca "no error -propenso". Hacer que sea obligatorio para las personas leer su función antes de usarla es una forma segura de que nunca se use. Indicando que necesita tres argumentos junto con sus valores predeterminados es menos propenso a errores porque las personas que llaman a su función sabrán a qué valores se aplicarán los parámetros por defecto, y confían en que presentarán el resultado que esperan.


Si el problema que está tratando de resolver es un muy grande número de argumentos, la decisión correcta es refactorizar sus funciones en otros más pequeños, no esconde detrás de las dependencias de la función de una matriz.

Cuestiones relacionadas