Spanish (Español) translation by Luis Chiabrera (you can also view the original English article)
¡Ahorre tiempo, reduzca los problemas de mantenimiento, simplifique su código y hágalo todo mientras se siente como un genio! En este tutorial, aprenda cómo usar variables variables, matrices de búsqueda y un poco de programación inteligente para simplificar el manejo de formularios de una manera considerable.
Variables variables, métodos y propiedades
Antes de poder profundizar en el uso de una matriz de búsqueda, es importante comprender primero el concepto detrás de las variables.
¿Qué son las variables variables?
Variable variablees un término, que describe el uso de una variable para declarar otra variable.
En la forma más simple, una variable variable podría verse como:
1 |
$foo = 'A value!'; // Declare an initial value |
2 |
$bar = 'foo'; // Wait, what's happening? |
3 |
echo $$bar; // Holy crap! That output 'A value!' |
¿Por qué debería importarte?
Cuando nos fijamos en una prueba de concepto como el ejemplo anterior, el uso de variables variables parece bastante tonto y demasiado complicado. Sin embargo, en realidad hay razones sólidas y prácticas para usarlas en algunos casos.


Ejemplos prácticos
El uso responsable de variables variables puede reducir drásticamente la cantidad de código que debe repetirse, por ejemplo, convirtiendo una matriz asociativa en un objeto con valores desinfectados.
Ejemplo sin variables variables
1 |
$comment = new stdClass(); // Create an object |
2 |
|
3 |
$comment->name = sanitize_value($array['name']); |
4 |
$comment->email = sanitize_values($array['email']); |
5 |
$comment->url = sanitize_values($array['url']); |
6 |
$comment->comment_text = sanitize_values($array['comment_text']); |
Ejemplo con variables variables
1 |
$comment = new stdClass(); // Create a new object |
2 |
|
3 |
foreach( $array as $key=>$val ) |
4 |
{
|
5 |
$comment->$key = sanitize_values($val); |
6 |
}
|
¿Ves cuanto más simple era eso? Y puedes imaginarte cómo se vería el ejemplo sin variables si la matriz tuviera algo como 50 o 100 valores.
NOTA: soy consciente de que también podría usar array_map () y emitir explícitamente la matriz como un objeto para lograr lo mismo. Ese no es el punto. Aquí estamos ilustrando un concepto. Seguir la corriente.
El problema con el procesamiento de formularios
Hacer que el procesamiento de formularios sea muy fácil.
Ahora que sabe cómo usar variables variables, podemos pasar a la carne y las papas de este artículo, que es la idea de que incorporar una matriz de búsqueda en lugar de varios archivos de controladores o una declaración de cambio puede ahorrarle mucho mantenimiento adicional. Código repetido, y dolor de cabeza en general.
Para ilustrar nuestro concepto, vamos a utilizar la idea de procesamiento de formularios. Este es un aspecto esencial de la programación web, y también puede ser una de las áreas más tediosas de cualquier proyecto.
Sin embargo, después de reevaluar sus hábitos de codificación, puede hacer que el procesamiento de formularios sea muy fácil.
Con frecuencia, se crea un archivo individual para cada formulario que se va a procesar o se usa una instrucción de cambio. En esta sección, veremos cómo se pueden implementar ambas soluciones, y luego examinaremos una solución utilizando variables variables y cómo puede mejorar sus proyectos.
Un ejemplo de trabajo con múltiples archivos de procesamiento de formularios
Un método que se usa con frecuencia para manejar el envío de formularios es crear un archivo completamente nuevo para manejar los datos de cada formulario por separado.
Tome, por ejemplo, estos tres formularios que actualizan una cuenta de usuario con un nombre nuevo, un nuevo correo electrónico o ambos:
1 |
<form action="assets/inc/ex1-form1.php" |
2 |
method="post" |
3 |
id="ex1-form1"> |
4 |
<div>
|
5 |
<h4>Form 1</h4> |
6 |
<label>Name
|
7 |
<input type="text" name="name" class="input-text" /> |
8 |
</label>
|
9 |
<input type="submit" class="input-submit" value="Submit" /> |
10 |
<input type="hidden" name="token" value="secret token goes here" /> |
11 |
</div>
|
12 |
</form>
|
13 |
|
14 |
<form action="assets/inc/ex1-form2.php" |
15 |
method="post" |
16 |
id="ex1-form2"> |
17 |
<div>
|
18 |
<h4>Form 2</h4> |
19 |
<label>Email
|
20 |
<input type="text" name="email" class="input-text" /> |
21 |
</label>
|
22 |
<input type="submit" class="input-submit" value="Submit" /> |
23 |
<input type="hidden" name="token" value="secret token goes here" /> |
24 |
</div>
|
25 |
</form>
|
26 |
|
27 |
<form action="assets/inc/ex1-form3.php" |
28 |
method="post" |
29 |
id="ex1-form3"> |
30 |
<div>
|
31 |
<h4>Form 3</h4> |
32 |
<label>Name
|
33 |
<input type="text" name="name" class="input-text" /> |
34 |
</label>
|
35 |
<label>Email
|
36 |
<input type="text" name="email" class="input-text" /> |
37 |
</label>
|
38 |
<input type="submit" class="input-submit" value="Submit" /> |
39 |
<input type="hidden" name="token" value="secret token goes here" /> |
40 |
</div>
|
41 |
</form>
|
Cada uno de estos formularios apunta a un archivo de procesamiento diferente. Entonces, ¿cómo se ve cada uno de estos archivos?
Formulario de procesamiento 1 (assets / inc / ex1-form1.php)
1 |
<?php
|
2 |
|
3 |
// Turn on error reporting so we can see if anything is going wrong
|
4 |
error_reporting(E_ALL); |
5 |
ini_set('display_errors', 1); |
6 |
|
7 |
// Make sure our faux-token was supplied
|
8 |
if( isset($_POST['token']) && $_POST['token']==='secret token goes here' ) |
9 |
{
|
10 |
// Require the necessary class
|
11 |
require_once 'class.copterlabs_account.inc.php'; |
12 |
|
13 |
// Create a new instance of the class
|
14 |
$account_obj = new CopterLabs_Account(); |
15 |
|
16 |
// Handle the form submission
|
17 |
$output = $account_obj->save_name(); |
18 |
|
19 |
// For this example, just output some data about the form submission
|
20 |
echo "<pre>Processing File: ", $_SERVER['PHP_SELF'], |
21 |
"\n\n<strong>Method Output:</strong>\n", $output, "</pre>\n", |
22 |
'<p><a href="../../">Go back</a></p>'; |
23 |
}
|
24 |
else
|
25 |
{
|
26 |
die( 'Invalid form submission' ); |
27 |
}
|
Formulario de procesamiento 2 (assets / inc / ex1-form2.php)
1 |
<?php
|
2 |
|
3 |
// Turn on error reporting so we can see if anything is going wrong
|
4 |
error_reporting(E_ALL); |
5 |
ini_set('display_errors', 1); |
6 |
|
7 |
// Make sure our faux-token was supplied
|
8 |
if( isset($_POST['token']) && $_POST['token']==='secret token goes here' ) |
9 |
{
|
10 |
// Require the necessary class
|
11 |
require_once 'class.copterlabs_account.inc.php'; |
12 |
|
13 |
// Create a new instance of the class
|
14 |
$account_obj = new CopterLabs_Account(); |
15 |
|
16 |
// Handle the form submission
|
17 |
$output = $account_obj->save_email(); |
18 |
|
19 |
// For this example, just output some data about the form submission
|
20 |
echo "<pre>Processing File: ", $_SERVER['PHP_SELF'], |
21 |
"\n\n<strong>Method Output:</strong>\n", $output, "</pre>\n", |
22 |
'<p><a href="../../">Go back</a></p>'; |
23 |
}
|
24 |
else
|
25 |
{
|
26 |
die( 'Invalid form submission' ); |
27 |
}
|
Formulario de procesamiento 3 (assets / inc / ex1-form3.php)
1 |
<?php
|
2 |
|
3 |
// Turn on error reporting so we can see if anything is going wrong
|
4 |
error_reporting(E_ALL); |
5 |
ini_set('display_errors', 1); |
6 |
|
7 |
// Make sure our faux-token was supplied
|
8 |
if( isset($_POST['token']) && $_POST['token']==='secret token goes here' ) |
9 |
{
|
10 |
// Require the necessary class
|
11 |
require_once 'class.copterlabs_account.inc.php'; |
12 |
|
13 |
// Create a new instance of the class
|
14 |
$account_obj = new CopterLabs_Account(); |
15 |
|
16 |
// Handle the form submission
|
17 |
$output = $account_obj->save_both(); |
18 |
|
19 |
// For this example, just output some data about the form submission
|
20 |
echo "<pre>Processing File: ", $_SERVER['PHP_SELF'], |
21 |
"\n\n<strong>Method Output:</strong>\n", $output, "</pre>\n", |
22 |
'<p><a href="../../">Go back</a></p>'; |
23 |
}
|
24 |
else
|
25 |
{
|
26 |
die( 'Invalid form submission' ); |
27 |
}
|
Como puede ver claramente, los archivos de ejemplo anteriores están duplicando una tonelada de código. Amplíe esto a 15 formularios en un sitio, y pronto descubrirá que el mantenimiento podría convertirse en una pesadilla.
La clase de cuenta
Como puede ver, los archivos de procesamiento están creando una instancia de la clase CopterLabs_Account. Esta será una clase muy simple que genera información sobre el envío de un formulario.
Aquí está el código para la clase (assets / inc / class.coperlabs_account.inc.php):
1 |
<?php
|
2 |
|
3 |
/**
|
4 |
* A simple class to test form submissions
|
5 |
*
|
6 |
* PHP version 5
|
7 |
*
|
8 |
* LICENSE: Dual licensed under the MIT or GPL licenses.
|
9 |
*
|
10 |
* @author Jason Lengstorf <jason.lengstorf@copterlabs.com>
|
11 |
* @copyright 2011 Copter Labs
|
12 |
* @license https://www.opensource.org/licenses/mit-license.html
|
13 |
* @license http://www.gnu.org/licenses/gpl-3.0.txt
|
14 |
*/
|
15 |
class CopterLabs_Account |
16 |
{
|
17 |
|
18 |
public $name = NULL, |
19 |
$email = NULL; |
20 |
|
21 |
public function save_name() |
22 |
{
|
23 |
$this->name = htmlentities($_POST['name'], ENT_QUOTES); |
24 |
|
25 |
return "Method: " . __METHOD__ . "\nName: " . $this->name . "\n"; |
26 |
}
|
27 |
|
28 |
public function save_email() |
29 |
{
|
30 |
$this->email = htmlentities($_POST['email'], ENT_QUOTES); |
31 |
|
32 |
return "Method: " . __METHOD__ . "\nEmail: " . $this->email . "\n"; |
33 |
}
|
34 |
|
35 |
public function save_both() |
36 |
{
|
37 |
$this->name = htmlentities($_POST['name'], ENT_QUOTES); |
38 |
$this->email = htmlentities($_POST['email'], ENT_QUOTES); |
39 |
|
40 |
return "Method: " . __METHOD__ . "\nName: " . $this->name . "\nEmail: " |
41 |
. $this->email . "\n"; |
42 |
}
|
43 |
|
44 |
}
|
Puede probar este código en el Ejemplo 1 en la página de demostración.
Un ejemplo de trabajo con un solo archivo de procesamiento y una declaración de cambio
Otra solución popular para el procesamiento de formularios es consolidar todos los scripts de procesamiento en un archivo y determinar qué hacer con los datos mediante una instrucción de cambio.
El enfoque de cambio comúnmente emplea un truco en el que se agrega una entrada oculta a la forma que contiene una acción que se debe realizar en el momento de la presentación. Esta
acción se usa para determinar qué hacer con el formulario.
Aquí están las mismas tres formas, desde arriba, con acciones agregadas, todas apuntando a un único archivo de procesamiento:
1 |
<form action="assets/inc/ex2-switch.php" |
2 |
method="post" |
3 |
id="ex2-form1"> |
4 |
<div>
|
5 |
<h4>Form 1</h4> |
6 |
<label>Name
|
7 |
<input type="text" name="name" class="input-text" /> |
8 |
</label>
|
9 |
<input type="submit" class="input-submit" value="Submit" /> |
10 |
<input type="hidden" name="action" value="update-name" /> |
11 |
<input type="hidden" name="token" value="secret token goes here" /> |
12 |
</div>
|
13 |
</form>
|
14 |
|
15 |
<form action="assets/inc/ex2-switch.php" |
16 |
method="post" |
17 |
id="ex2-form2"> |
18 |
<div>
|
19 |
<h4>Form 2</h4> |
20 |
<label>Email
|
21 |
<input type="text" name="email" class="input-text" /> |
22 |
</label>
|
23 |
<input type="submit" class="input-submit" value="Submit" /> |
24 |
<input type="hidden" name="action" value="update-email" /> |
25 |
<input type="hidden" name="token" value="secret token goes here" /> |
26 |
</div>
|
27 |
</form>
|
28 |
|
29 |
<form action="assets/inc/ex2-switch.php" |
30 |
method="post" |
31 |
id="ex2-form3"> |
32 |
<div>
|
33 |
<h4>Form 3</h4> |
34 |
<label>Name
|
35 |
<input type="text" name="name" class="input-text" /> |
36 |
</label>
|
37 |
<label>Email
|
38 |
<input type="text" name="email" class="input-text" /> |
39 |
</label>
|
40 |
<input type="submit" class="input-submit" value="Submit" /> |
41 |
<input type="hidden" name="action" value="update-both" /> |
42 |
<input type="hidden" name="token" value="secret token goes here" /> |
43 |
</div>
|
44 |
</form>
|
Y el nuevo archivo de procesamiento se parece a: (assets / inc / ex2-switch.php)
1 |
<?php
|
2 |
|
3 |
// Turn on error reporting so we can see if anything is going wrong
|
4 |
error_reporting(E_ALL); |
5 |
ini_set('display_errors', 1); |
6 |
|
7 |
// Make sure our faux-token was supplied
|
8 |
if( isset($_POST['token']) && $_POST['token']==='secret token goes here' ) |
9 |
{
|
10 |
// Require the necessary class
|
11 |
require_once 'class.copterlabs_account.inc.php'; |
12 |
|
13 |
// Create a new instance of the class
|
14 |
$account_obj = new CopterLabs_Account(); |
15 |
|
16 |
// Sanitize the action
|
17 |
$action = htmlentities($_POST['action'], ENT_QUOTES); |
18 |
|
19 |
// Use the new 'action' hidden input to determine what action to call
|
20 |
switch( $action ) |
21 |
{
|
22 |
// Form 1 handling
|
23 |
case 'update-name': |
24 |
$output = $account_obj->save_name(); |
25 |
break; |
26 |
|
27 |
// Form 2 handling
|
28 |
case 'update-email': |
29 |
$output = $account_obj->save_email(); |
30 |
break; |
31 |
|
32 |
// Form 3 handling
|
33 |
case 'update-both': |
34 |
$output = $account_obj->save_both(); |
35 |
break; |
36 |
|
37 |
// If no valid action is found, something isn't right
|
38 |
default: |
39 |
die( 'Unsupported action.' ); |
40 |
}
|
41 |
|
42 |
// For this example, just output some data about the form submission
|
43 |
echo "<pre>Processing File: ", $_SERVER['PHP_SELF'], |
44 |
"\nAction: ", htmlentities($_POST['action'], ENT_QUOTES), |
45 |
"\n\n<strong>Method Output:</strong>\n", $output, "</pre>\n", |
46 |
'<p><a href="../../#ex2">Go back to example 2</a></p>'; |
47 |
}
|
48 |
else
|
49 |
{
|
50 |
die( 'Invalid form submission' ); |
51 |
}
|
Puede ver esto en acción visitando el Ejemplo 2 en la página de demostración. Esta es una mejora marcada en el uso de múltiples formularios, pero puede ver que todavía estamos duplicando algún código.
Además de eso, es una de mis preferencias personales evitar el cambio de declaraciones siempre que puedo. Esto se debe al hecho de que el conmutador usa comparaciones sueltas ('una cadena' activará el caso 0 porque una cadena se evalúa a 0 si la convierte en un número entero) y es extremadamente fácil de convertir en código spaghetti.
Arreglando el Problema: Arreglos de Búsqueda y Variables Variables
Como hemos visto hasta ahora, ambas soluciones anteriores tienen sus inconvenientes y requieren un código duplicado. Imagínese si hubiera una docena o más formas en el sitio, no es bonito.
Para solucionar este problema, podemos usar un concepto llamado matriz de búsqueda, que asigna las acciones pasadas desde el formulario a un método llamado en el objeto.
Sí, podría establecer la acción como el nombre del método, pero eso permite que un envío de formulario falso llame a cualquier método público. Hacer que la matriz sea un par clave-valor es un pequeño paso para agregar un poco más de control sin mucho trabajo adicional.
Un ejemplo de trabajo con un solo archivo de procesamiento y una matriz de búsqueda
Usando nuestro conocimiento de las variables desde el comienzo de este tutorial, modifiquemos nuestra demostración para usar una matriz de búsqueda.
Modifique los tres formularios para que apunten a un nuevo archivo de controlador:
1 |
<form action="assets/inc/ex3-lookup-array.php" |
2 |
method="post" |
3 |
id="ex3-form1"> |
4 |
<div>
|
5 |
<h4>Form 1</h4> |
6 |
<label>Name
|
7 |
<input type="text" name="name" class="input-text" /> |
8 |
</label>
|
9 |
<input type="submit" class="input-submit" value="Submit" /> |
10 |
<input type="hidden" name="action" value="update-name" /> |
11 |
<input type="hidden" name="token" value="secret token goes here" /> |
12 |
</div>
|
13 |
</form>
|
14 |
|
15 |
<form action="assets/inc/ex3-lookup-array.php" |
16 |
method="post" |
17 |
id="ex3-form2"> |
18 |
<div>
|
19 |
<h4>Form 2</h4> |
20 |
<label>Email
|
21 |
<input type="text" name="email" class="input-text" /> |
22 |
</label>
|
23 |
<input type="submit" class="input-submit" value="Submit" /> |
24 |
<input type="hidden" name="action" value="update-email" /> |
25 |
<input type="hidden" name="token" value="secret token goes here" /> |
26 |
</div>
|
27 |
</form>
|
28 |
|
29 |
<form action="assets/inc/ex3-lookup-array.php" |
30 |
method="post" |
31 |
id="ex3-form3"> |
32 |
<div>
|
33 |
<h4>Form 3</h4> |
34 |
<label>Name
|
35 |
<input type="text" name="name" class="input-text" /> |
36 |
</label>
|
37 |
<label>Email
|
38 |
<input type="text" name="email" class="input-text" /> |
39 |
</label>
|
40 |
<input type="submit" class="input-submit" value="Submit" /> |
41 |
<input type="hidden" name="action" value="update-both" /> |
42 |
<input type="hidden" name="token" value="secret token goes here" /> |
43 |
</div>
|
44 |
</form>
|
A continuación, reúna el archivo de procesamiento que manejará los envíos de formularios (assets / inc / ex3-lookup-array.php):
1 |
<?php
|
2 |
|
3 |
// Turn on error reporting so we can see if anything is going wrong
|
4 |
error_reporting(E_ALL); |
5 |
ini_set('display_errors', 1); |
6 |
|
7 |
// Make sure our faux-token was supplied
|
8 |
if( isset($_POST['token']) && $_POST['token']==='secret token goes here' ) |
9 |
{
|
10 |
// Require the necessary class
|
11 |
require_once 'class.copterlabs_account.inc.php'; |
12 |
|
13 |
// Create a new instance of the class
|
14 |
$account_obj = new CopterLabs_Account(); |
15 |
|
16 |
// Sanitize the action
|
17 |
$action = htmlentities($_POST['action'], ENT_QUOTES); |
18 |
|
19 |
// Set up a lookup array to match actions to method names
|
20 |
$lookup_array = array( |
21 |
'update-name' => 'save_name', |
22 |
'update-email' => 'save_email', |
23 |
'update-both' => 'save_both' |
24 |
);
|
25 |
|
26 |
// Make sure the array key exists
|
27 |
if( array_key_exists($action, $lookup_array) ) |
28 |
{
|
29 |
// Using variable variables, call the proper method and store the output
|
30 |
$output = $account_obj->$lookup_array[$action](); |
31 |
}
|
32 |
else
|
33 |
{
|
34 |
die( 'Unsupported action.' ); |
35 |
}
|
36 |
|
37 |
// For this example, just output some data about the form submission
|
38 |
echo "<pre>Processing File: ", $_SERVER['PHP_SELF'], |
39 |
"\nAction: ", htmlentities($_POST['action'], ENT_QUOTES), |
40 |
"\n\n<strong>Method Output:</strong>\n", $output, "</pre>\n", |
41 |
'<p><a href="../../#ex3">Go back to example 3</a></p>'; |
42 |
}
|
43 |
else
|
44 |
{
|
45 |
die( 'Invalid form submission' ); |
46 |
}
|
Verifique esto en la página de demostración probando los formularios en el Ejemplo 3.
Ya que establecemos la acción como la clave en la matriz, usamos array_key_exists () para asegurarnos de que la acción sea válida. Luego, usamos el valor que corresponde a la acción como el nombre del método. Observe que agregamos los paréntesis después del valor para asegurarnos de que se ejecute como un método.
La adición de la matriz de búsqueda mantiene el código conciso, simple y claro (una vez que se obtiene el bloqueo de las variables).
Resumen
Usados responsablemente, las matrices de búsqueda pueden hacer que sus scripts sean mucho más fáciles de actualizar y mantener cuando los combina con variables variables.
¿Cómo cree que puede integrar matrices de búsqueda y variables en sus proyectos para facilitar el mantenimiento? ¡Házmelo saber en los comentarios!



