2011-12-19 32 views
16

Tengo algunos métodos de "setter" en todas las clases, y por comodidad he agregado un parámetro opcional $previous, que toma un argumento por referencia y lo rellena con el valor existente antes de reemplazarlo por el nuevo uno. Por ejemplo:Probando argumentos opcionales en PHP

public function set_value($key, $value, &$previous = null) 
{ 
    $previous = $this->get_value($key); 
    $this->_values[$key] = $value; 
    return $this; 
} 

Esto funciona bien; sin embargo, en algunas circunstancias, el método "getter" correspondiente consume un poco de proceso, y ejecutarlo incondicionalmente es un desperdicio. Pensé que podría probar:

if(null !== $previous) 
{ 
    $previous = $this->get_value($key); 
} 

Esto no funciona, sin embargo, tan a menudo la variable utilizada como argumento para $previous no se ha definido previamente en su ámbito de aplicación, y por defecto en null de todos modos. La única solución que he hackeado a cabo es:

public function set_value($key, $value, &$previous = null) 
{ 
    $args = func_get_args(); 
    if(isset($args[2]) 
    { 
     $previous = $this->get_value($key); 
    } 
    $this->_values[$key] = $value; 
    return $this; 
} 

O, para una línea que:

if(array_key_exists(2, func_get_args())) 
{ 
    // ... 
} 

no me gusta el cuerpo del método siendo dependientes de los índices de argumentos (cuando parece que debería ser innecesario) ¿Hay una manera más clara de lograr lo que busco aquí?


He intentado:

if(isset($previous)){} 

if(!empty($previous)){} 

if(null !== $previous){} 

Ni trabajo.

soluciones posibles hasta el momento:

if(func_num_args() == $num_params){} 

if(array_key_exists($param_index, func_get_args())){} 

// 5.4 
if(isset(func_get_args()[$param_index])){} 

// 5.4 
if(func_num_args() == (new \ReflectionMethod(__CLASS__, __FUNCTION__)) 
    ->getNumberOfParameters()){} 

@DaveRandom - Por lo tanto, algo en el área de:

define('_NOPARAM', '_NOPARAM' . hash('sha4096', microtime())); 

function foo($bar = _NOPARAM) 
{ 
    // ... 
} 

@hoppa - caso de uso:

$obj->set_something('some_key', $some_value, $previous) // set 
    ->do_something_that_uses_some_key() 
    ->set_something('some_key', $previous) // and reset 
    ->do_something_that_uses_some_key() 
    -> ... 

En lugar de:

$previous = $obj->get_something('some_key'); // get 
$obj->set_something('some_key', $some_value) // set 
    ->do_something_that_uses_some_key(); 
    ->set_something($previous) // and reset 
    ->do_something_that_uses_some_key(); 
    -> ... 
+3

no Podría definir el valor por defecto para '$ previous' como FALSE (o algún valor de la" tipo "incorrecto" - entonces usted sabe que es 'nulo' que fue aprobado, pero es' FALSO' (o lo que sea) que no fue. Este método también tiene agujeros (el usuario puede pasar su valor predeterminado), pero creo que sería un enfoque decente, especialmente si convierte el valor predeterminado en una cadena aleatoria larga que es muy poco probable que esté en la variable que se pasó . – DaveRandom

+0

@DaveRandom - El valor anterior podría ser un booleano 'false' en algunas circunstancias. Elegí 'null' por su intención semántica," ausencia de valor ". – Dan

+0

Vea el comentario editado sobre la cadena larga aleatoria - Admito que no es un enfoque bonito o perfecto, pero es un enfoque de 99.99999% de trabajos ... – DaveRandom

Respuesta

3
posiblemente no

cómo lo quería para resolver su problema (prueba argumentos de alguna manera opcional), pero así es como me gustaría ponerlo en práctica:

public function set_value($key, $value) 
{ 
    $this->_values[$key] = $value; 
    return $this; 
} 
public function set_get_value($key, $value, &$previous) 
{ 
    $previous = $this->get_value($key); 
    $this->_values[$key] = $value; 
    return $this; 
} 

Uso ejemplo de caso:

$obj->set_get_something('some_key', $some_value, $previous) // set AND get 
    ->do_something_that_uses_some_key() 
    ->set_something('some_key', $previous) // and reset 
    ->do_something_that_uses_some_key() 
    -> ... 

¿Por qué usar otra función?

Esta solución tiene algunas ventajas:

  1. el nombre es más explícito, menos confusión para otros codificadores
  2. sin efectos secundarios ocultos
  3. resuelve su problema con las variables (no definidos) que ya tienen una
  4. valor
  5. sin sobrecarga de llamar func_num_args, o alguna otra función "meta"

EDIT: error en el código.

EDIT 2: eliminado valor predeterminado de set_get_value anterior & $() función (gracias a draevor)

+0

Buena alternativa. Una pequeña corrección - '& $ previous' no necesita tener un valor predeterminado en la segunda función, está destinado a estar allí. – deviousdodo

+0

de hecho :) editado! – catchmeifyoutry

1

Extraído de la comentarios/discusión anterior:

Con el fin de comprobar si se pasa el argumento de que tienen 2 opciones - comprobar el valor del argumento en contra de un valor (como se he terminado con nulo) o verifica la cantidad de argumentos.

Si va con la primera opción, no hay ningún valor que no se pueda pasar desde fuera de la función, por lo que siempre habrá una posibilidad de falsos positivos (lo mismo que está sucediendo ahora con nulo). El ejemplo de DaveRandom con una secuencia aleatoria debería ser suficiente para la mayoría de los casos, pero lo veo como excesivo.

Creo que la segunda opción es la más limpia (rápida, legible, etc.). Como pequeña mejora con respecto a lo que ya ha hecho con func_get_args, usaría func_num_args - de esta manera comprobará el número de argumentos pasados, no los índices de argumento.

+0

Gracias @draevor - Verifique mi edición en "* He intentado/Posibles soluciones *", la última (* una vez que 5.4 toque las calles *) funcionaría bien para la reutilización de clase agnóstica en un rasgo, dado el ' El parámetro $ previous' siempre es el último. Como dije antes, su respuesta es ciertamente la mejor candidata, dejaré que esto se quede un rato, y marcaré la suya si nada sale de la carpintería. – Dan

Cuestiones relacionadas