variable solucion nombre index indefinido php null pass-by-reference

solucion - Parámetros de referencia por PHP y valor predeterminado nulo



notice undefined index nombre in (6)

Digamos que tenemos una firma de método como

public static function explodeDn($dn, array &$keys = null, array &$vals = null, $caseFold = self::ATTR_CASEFOLD_NONE)

podemos llamar fácilmente al método omitiendo todos los parámetros después de $dn :

$dn=Zend_Ldap_Dn::explodeDn(''CN=Alice Baker,CN=Users,DC=example,DC=com'');

También podemos llamar al método con 3 parámetros:

$dn=Zend_Ldap_Dn::explodeDn(''CN=Alice Baker,CN=Users,DC=example,DC=com'', $k, $v);

y con 4 parámetros:

$dn=Zend_Ldap_Dn::explodeDn(''CN=Alice Baker,CN=Users,DC=example,DC=com'', $k, $v, Zend_Ldap_Dn::ATTR_CASEFOLD_UPPER);

Pero ¿por qué es imposible llamar al método con la siguiente combinación de parámetros, por ejemplo:

$dn=Zend_Ldap_Dn::explodeDn(''CN=Alice Baker,CN=Users,DC=example,DC=com'', $k, null, Zend_Ldap_Dn::ATTR_CASEFOLD_UPPER); $dn=Zend_Ldap_Dn::explodeDn(''CN=Alice Baker,CN=Users,DC=example,DC=com'', null, $v);

¿Cuál es la diferencia entre pasar el método null al método y confiar en el valor predeterminado? ¿Esta restricción está escrita en el manual? ¿Se puede eludir?


Es porque no puedes tener una referencia a nulo.

Puede tener una referencia a una variable que contiene nulo; eso es exactamente lo que hace el valor predeterminado. O puede pasar nulo como un valor literal, pero dado que desea un parámetro de salida, esto no es posible aquí.


@ Tomalak

En realidad, el valor predeterminado crea una variable sin ninguna referencia involucrada. Que es algo que simplemente no puedes patear cuando pasas algo.

Lo que encuentro para ilustrar las razones es el siguiente ejemplo (que no probé):

function foo (&$ref = NULL) { $args = func_get_args(); echo var_export($ref, TRUE).'' - ''.var_export($args, TRUE); } $bar = NULL; foo(); // NULL - array() foo($bar); // NULL - array(0 => NULL)

En mi opinión, PHP debería ofrecer una forma de NO pasar ciertos parámetros, como con
foo($p1, , , $p4); o una sintaxis similar en lugar de pasar NULL.
Pero no es así, entonces debes usar variables ficticias.


Me acabo de enterar de esto, y estoy bastante en shock o_O!

Esto es lo que dice la documentación PHP :

function makecoffee($type = "cappuccino") { return "Making a cup of $type./n"; } echo makecoffee(); // returns "Making a cup of cappuccino." echo makecoffee(null); // returns "Making a cup of ." echo makecoffee("espresso"); // returns "Making a cup of espresso."

Hubiera esperado que makecoffee(null) devolviera "Hacer una taza de capuchino". Una solución alternativa que he usado es verificar dentro de la función si el argumento es nulo:

function makecoffee($type = null) { if (is_null($type)){ $type = "capuccino"; } return "Making a cup of $type./n"; }

Ahora makecoffee(null) devuelve "Hacer una taza de capuchino".

(Me doy cuenta de que esto no resuelve realmente la pregunta relacionada con Zend, pero podría ser útil para algunos ...)


Si bien debe crear una variable ficticia para los argumentos de by-ref si desea pasar NULL explícitamente, no tiene que crear esa variable en una línea separada. Puede usar una expresión de asignación como $ dummy = NULL directamente como un argumento de función:

function foo (&$ref = NULL) { if (is_null($ref)) $ref="bar"; echo "$ref/n"; } foo($dummy = NULL); //this works!


Como @aschmecher señaló en un comentario sobre la respuesta de @Szczepan aquí , al hacer func($var = null) genera un estricto aviso de estándares.

Una solución

Aquí hay un método que no genera tales advertencias:

<?php error_reporting(E_ALL | E_STRICT); function doIt(&$x = null) { if($x !== null) echo "x not null: $x/n"; $x = 2; } function &dummyRef() { $dummyRef = null; return $dummyRef; } doIt(dummyRef()); doIt(dummyRef());

Explicación

En lugar de pasar una variable, pasamos el resultado de una función que devuelve una referencia. La segunda llamada a doIt(dummy()) es para verificar que el valor de $dummy referencia no persista entre llamadas. Esto contrasta con la creación explícita de una variable, donde es necesario recordar borrar cualquier valor acumulado:

$dummyRef = null; doIt($dummyRef); doIt($dummyRef); // second call would print ''x not null: 2''

Solicitud

Entonces en el ejemplo de OP, sería:

$dn = Zend_Ldap_Dn::explodeDn( ''CN=Alice Baker,CN=Users,DC=example,DC=com'', $k, dummyRef(), Zend_Ldap_Dn::ATTR_CASEFOLD_UPPER );

Consideraciones adicionales

Una cosa que podría preocuparme es si este método crea una pérdida de memoria. La siguiente prueba muestra que no:

<?php function doItObj(&$x = null) { if(gettype($x) !== "object") echo "x not null: $x/n"; $x = 2; } function &dummyObjRef() { $dummyObjRef = new StdClass(); return $dummyObjRef; } echo "memory before: " . memory_get_usage(true) . "/n"; for($i = 0; $i < 1000000; $i++) { doItObj(dummyObjRef()); } echo "memory after: " . memory_get_usage(true) . "/n"; echo "/n$i/n";

En mi sistema (usando PHP 5.6.4), ambas llamadas a memory_get_usage mostraron ~ 262 KB.


Solo para confirmar lo que Tomalak declaró aquí :

Los siguientes trabajos:

$k=array(); $v=null; $dn=Zend_Ldap_Dn::explodeDn(''CN=Alice Baker,CN=Users,DC=example,DC=com'', $k, $v, Zend_Ldap_Dn::ATTR_CASEFOLD_UPPER);

No es agradable, pero la explicación es clara y comprensible.