Pregunta

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 null al método y confiar en el valor predeterminado? ¿Esta restricción está escrita en el manual? ¿Se puede eludir?

¿Fue útil?

Solución

Es porque no puede tener una referencia a nulo.

Puede tener una referencia a una variable que contenga 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í.

Otros consejos

Si bien debe crear una variable ficticia para argumentos 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 argumento de función:

function foo (&$ref = NULL) {

    if (is_null($ref)) $ref="bar";
    echo "$ref\n";        
}

foo($dummy = NULL); //this works!

¡Acabo de descubrir esto yo mismo, y estoy bastante en shock o_O!

Esto es lo que la documentación PHP dice:

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) volviera " Hacer una taza de capuchino. " ;. Una solución 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 en realidad no resuelve la pregunta relacionada con Zend, pero podría ser útil para algunos ...)

@ Tomalak

En realidad, el valor predeterminado crea una variable sin ninguna referencia involucrada. Es algo que simplemente no puedes iniciar 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 manera de NO pasar ciertos parámetros, como con
foo ($ p1,,, $ p4); o una sintaxis similar en lugar de pasar NULL.
Pero no es así, por lo que debe usar variables ficticias.

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.

Como señaló @aschmecher en un comentario sobre La respuesta de @ Szczepan aquí , haciendo 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 referencia $ dummy no persiste entre llamadas. Esto contrasta con la creación de una variable explícitamente, donde uno debe recordar borrar cualquier valor acumulado:

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

Aplicación

Entonces, en el ejemplo del 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 me preocupa es si este método crea una pérdida de memoria. La siguiente prueba muestra que no es así:

<?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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top