Spanish (Español) translation by Jorge Montoya (you can also view the original English article)
Dos veces por mes, volvemos a visitar algunas de las publicaciones favoritas de nuestros lectores a lo largo de toda la historia de Nettuts+.
Incluso después de utilizar PHP por años, nos tropezamos con funciones y características que no conocíamos. Algunas de estas pueden ser muy útiles, sin embargo subutilizadas. Con eso en mente, he compilado una lista de nueve funciones y características increíbles de PHP con las que usted debería familiarizarse.
1. Funciones con un Número Arbitrario de Argumentos
Ya puede que ya sepa que PHP le permite definir funciones con argumentos opcionales. Pero también existe un método para permitir un número completamente arbitrario de argumentos de función.
En primer lugar, aquí hay un ejemplo solo con argumentos opcionales:
1 |
|
2 |
// function with 2 optional arguments
|
3 |
function foo($arg1 = '', $arg2 = '') { |
4 |
|
5 |
echo "arg1: $arg1\n"; |
6 |
echo "arg2: $arg2\n"; |
7 |
|
8 |
}
|
9 |
|
10 |
|
11 |
foo('hello','world'); |
12 |
/* prints:
|
13 |
arg1: hello
|
14 |
arg2: world
|
15 |
*/
|
16 |
|
17 |
foo(); |
18 |
/* prints:
|
19 |
arg1:
|
20 |
arg2:
|
21 |
*/
|
Ahora, veamos cómo podemos construir una función que acepte cualquier número de argumentos. Esta vez vamos a utilizar func_get_args():
1 |
|
2 |
// yes, the argument list can be empty
|
3 |
function foo() { |
4 |
|
5 |
// returns an array of all passed arguments
|
6 |
$args = func_get_args(); |
7 |
|
8 |
foreach ($args as $k => $v) { |
9 |
echo "arg".($k+1).": $v\n"; |
10 |
}
|
11 |
|
12 |
}
|
13 |
|
14 |
foo(); |
15 |
/* prints nothing */
|
16 |
|
17 |
foo('hello'); |
18 |
/* prints
|
19 |
arg1: hello
|
20 |
*/
|
21 |
|
22 |
foo('hello', 'world', 'again'); |
23 |
/* prints
|
24 |
arg1: hello
|
25 |
arg2: world
|
26 |
arg3: again
|
27 |
*/
|
2. Uso de Glob() para Encontrar Archivos
Muchas funciones de PHP tienen nombres largos y descriptivos. Sin embargo, puede ser difícil saber qué hace una función llamada glob() a menos que ya esté familiarizado con ese término de otra parte.
Piense en ello como una versión más capaz de la función scandir(). Puede permitirte buscar archivos usando patrones.
1 |
|
2 |
// get all php files
|
3 |
$files = glob('*.php'); |
4 |
|
5 |
print_r($files); |
6 |
/* output looks like:
|
7 |
Array
|
8 |
(
|
9 |
[0] => phptest.php
|
10 |
[1] => pi.php
|
11 |
[2] => post_output.php
|
12 |
[3] => test.php
|
13 |
)
|
14 |
*/
|
Puede obtener varios tipos de archivo como este:
1 |
|
2 |
// get all php files AND txt files
|
3 |
$files = glob('*.{php,txt}', GLOB_BRACE); |
4 |
|
5 |
print_r($files); |
6 |
/* output looks like:
|
7 |
Array
|
8 |
(
|
9 |
[0] => phptest.php
|
10 |
[1] => pi.php
|
11 |
[2] => post_output.php
|
12 |
[3] => test.php
|
13 |
[4] => log.txt
|
14 |
[5] => test.txt
|
15 |
)
|
16 |
*/
|
Tenga en cuenta que los archivos pueden ser devueltos con una ruta, dependiendo de su consulta:
1 |
|
2 |
$files = glob('../images/a*.jpg'); |
3 |
|
4 |
print_r($files); |
5 |
/* output looks like:
|
6 |
Array
|
7 |
(
|
8 |
[0] => ../images/apple.jpg
|
9 |
[1] => ../images/art.jpg
|
10 |
)
|
11 |
*/
|
Si desea obtener la ruta completa a cada archivo, sólo puede llamar a la función realpath() en los valores devueltos:
1 |
|
2 |
$files = glob('../images/a*.jpg'); |
3 |
|
4 |
// applies the function to each array element
|
5 |
$files = array_map('realpath',$files); |
6 |
|
7 |
print_r($files); |
8 |
/* output looks like:
|
9 |
Array
|
10 |
(
|
11 |
[0] => C:\wamp\www\images\apple.jpg
|
12 |
[1] => C:\wamp\www\images\art.jpg
|
13 |
)
|
14 |
*/
|
3. Información Sobre el Uso de la Memoria
Observando el uso de la memoria de sus scripts, puede optimizar mejor su código.
PHP tiene un recolector de basura y un administrador de memoria bastante complejo. La cantidad de memoria utilizada por el script. puede subir y bajar durante la ejecución de un script. Para obtener el uso actual de la memoria, podemos usar la función memory_get_usage(), y para obtener la mayor cantidad de memoria utilizada en cualquier punto, podemos usar la función memory_get_peak_usage().
1 |
|
2 |
echo "Initial: ".memory_get_usage()." bytes \n"; |
3 |
/* prints
|
4 |
Initial: 361400 bytes
|
5 |
*/
|
6 |
|
7 |
// let's use up some memory
|
8 |
for ($i = 0; $i < 100000; $i++) { |
9 |
$array []= md5($i); |
10 |
}
|
11 |
|
12 |
// let's remove half of the array
|
13 |
for ($i = 0; $i < 100000; $i++) { |
14 |
unset($array[$i]); |
15 |
}
|
16 |
|
17 |
echo "Final: ".memory_get_usage()." bytes \n"; |
18 |
/* prints
|
19 |
Final: 885912 bytes
|
20 |
*/
|
21 |
|
22 |
echo "Peak: ".memory_get_peak_usage()." bytes \n"; |
23 |
/* prints
|
24 |
Peak: 13687072 bytes
|
25 |
*/
|
4. Información de Uso de la CPU
Para ello, vamos a utilizar la función getrusage(). Tenga en cuenta que esto no está disponible en plataformas Windows.
1 |
|
2 |
print_r(getrusage()); |
3 |
/* prints
|
4 |
Array
|
5 |
(
|
6 |
[ru_oublock] => 0
|
7 |
[ru_inblock] => 0
|
8 |
[ru_msgsnd] => 2
|
9 |
[ru_msgrcv] => 3
|
10 |
[ru_maxrss] => 12692
|
11 |
[ru_ixrss] => 764
|
12 |
[ru_idrss] => 3864
|
13 |
[ru_minflt] => 94
|
14 |
[ru_majflt] => 0
|
15 |
[ru_nsignals] => 1
|
16 |
[ru_nvcsw] => 67
|
17 |
[ru_nivcsw] => 4
|
18 |
[ru_nswap] => 0
|
19 |
[ru_utime.tv_usec] => 0
|
20 |
[ru_utime.tv_sec] => 0
|
21 |
[ru_stime.tv_usec] => 6269
|
22 |
[ru_stime.tv_sec] => 0
|
23 |
)
|
24 |
|
25 |
*/
|
Eso puede parecer un poco críptico a menos que ya tenga un conocimientos de administración de sistema. Aquí está la explicación de cada valor (no es necesario memorizarlos):
- ru_oublock: bloquear operaciones de salida
- ru_inblock: bloquear operaciones de entrada
- ru_msgsnd: mensajes enviados
- ru_msgrcv: mensajes recibidos
- ru_maxrss: tamaño máximo del conjunto de residentes
- ru_ixrss: tamaño de memoria compartida integral
- ru_idrss: tamaño de datos sin compartir
- ru_minflt: reclamaciones de página
- ru_majflt: fallos de página
- ru_nsignals: señales recibidas
- ru_nvcsw: cambios de contexto voluntarios
- ru_nivcsw: cambios involuntarios de contexto
- ru_nswap: intercambios
- ru_utime.tv_usec: tiempo de usuario utilizado (microsegundos)
- ru_utime.tv_sec: tiempo de uso del usuario (segundos)
- ru_stime.tv_usec: tiempo del sistema utilizado (microsegundos)
- ru_stime.tv_sec: tiempo del sistema utilizado (segundos)
Para ver cuánta potencia de CPU consumió el script, debemos mirar los valores de 'tiempo de usuario' y 'tiempo de sistema'. Las porciones de segundos y microsegundos se proporcionan por separado por defecto. Puede dividir el valor de microsegundos en 1 millón y agregarlo al valor de segundos, para obtener el total de segundos como un número decimal.
Veamos un ejemplo:
1 |
|
2 |
// sleep for 3 seconds (non-busy)
|
3 |
sleep(3); |
4 |
|
5 |
$data = getrusage(); |
6 |
echo "User time: ". |
7 |
($data['ru_utime.tv_sec'] + |
8 |
$data['ru_utime.tv_usec'] / 1000000); |
9 |
echo "System time: ". |
10 |
($data['ru_stime.tv_sec'] + |
11 |
$data['ru_stime.tv_usec'] / 1000000); |
12 |
|
13 |
/* prints
|
14 |
User time: 0.011552
|
15 |
System time: 0
|
16 |
*/
|
A pesar de que el script tomó unos 3 segundos para ejecutarse, el uso de la CPU fue muy, muy bajo. Porque durante la operación de suspensión, el script realmente no consume recursos de CPU. Hay muchas otras tareas que pueden tomar tiempo real, pero no puede utilizar el tiempo de CPU, como esperar operaciones de disco. Por lo tanto, como puede ver, el uso de la CPU y la duración real del tiempo de ejecución no siempre son los mismos.
Aquí hay otro ejemplo:
1 |
|
2 |
// loop 10 million times (busy)
|
3 |
for($i=0;$i<10000000;$i++) { |
4 |
|
5 |
}
|
6 |
|
7 |
$data = getrusage(); |
8 |
echo "User time: ". |
9 |
($data['ru_utime.tv_sec'] + |
10 |
$data['ru_utime.tv_usec'] / 1000000); |
11 |
echo "System time: ". |
12 |
($data['ru_stime.tv_sec'] + |
13 |
$data['ru_stime.tv_usec'] / 1000000); |
14 |
|
15 |
/* prints
|
16 |
User time: 1.424592
|
17 |
System time: 0.004204
|
18 |
*/
|
Eso llevó alrededor de 1,4 segundos de tiempo de la CPU, casi todo el tiempo del usuario, ya que no había llamadas del sistema.
El Tiempo del Sistema es la cantidad de tiempo que la CPU pasa realizando llamadas del sistema para el kernel en nombre del programa. Aquí hay un ejemplo de eso:
1 |
|
2 |
$start = microtime(true); |
3 |
// keep calling microtime for about 3 seconds
|
4 |
while(microtime(true) - $start < 3) { |
5 |
|
6 |
}
|
7 |
|
8 |
$data = getrusage(); |
9 |
echo "User time: ". |
10 |
($data['ru_utime.tv_sec'] + |
11 |
$data['ru_utime.tv_usec'] / 1000000); |
12 |
echo "System time: ". |
13 |
($data['ru_stime.tv_sec'] + |
14 |
$data['ru_stime.tv_usec'] / 1000000); |
15 |
|
16 |
/* prints
|
17 |
User time: 1.088171
|
18 |
System time: 1.675315
|
19 |
*/
|
Ahora tenemos un bastante tiempo de uso del sistema. Esto se debe a que el script llama a la función microtime() muchas veces, lo que realiza una solicitud a través del sistema operativo para obtener la hora.
También puede notar que los números no suman hasta 3 segundos. Esto es porque probablemente hay otros procesos en el servidor, así, y el script no estaba usando 100% de la CPU durante toda la duración de los 3 segundos.
5. Constantes Mágicas
PHP proporciona constantes mágicas útiles para buscar el número de línea actual (__LINE__), la ruta del archivo (__FILE__), la ruta del directorio (__DIR__), el nombre de la función (__FUNCTION__), el nombre de la clase (__CLASS__), el nombre del método (__METHOD__) y el espacio de nombre (__NAMESPACE__).
No vamos a cubrir cada uno de estos en este artículo, pero voy a mostrar algunos casos de uso.
Al incluir otros scripts, es una buena idea utilizar la constante
__FILE__(o también__DIR__, a partir de PHP 5.3):
1 |
|
2 |
// this is relative to the loaded script's path
|
3 |
// it may cause problems when running scripts from different directories
|
4 |
require_once('config/database.php'); |
5 |
|
6 |
// this is always relative to this file's path
|
7 |
// no matter where it was included from
|
8 |
require_once(dirname(__FILE__) . '/config/database.php'); |
El uso de __LINE__ facilita la depuración. Puede rastrear los números de línea:
1 |
|
2 |
// some code
|
3 |
// ...
|
4 |
my_debug("some debug message", __LINE__); |
5 |
/* prints
|
6 |
Line 4: some debug message
|
7 |
*/
|
8 |
|
9 |
// some more code
|
10 |
// ...
|
11 |
my_debug("another debug message", __LINE__); |
12 |
/* prints
|
13 |
Line 11: another debug message
|
14 |
*/
|
15 |
|
16 |
function my_debug($msg, $line) { |
17 |
echo "Line $line: $msg\n"; |
18 |
}
|
6. Generación de IDs Únicos
Puede haber situaciones en las que necesite generar una cadena única. He visto a muchas personas usar la función md5() para esto, aunque no es exactamente para este propósito:
1 |
|
2 |
// generate unique string
|
3 |
echo md5(time() . mt_rand(1,1000000)); |
En realidad, existe una función PHP llamada uniqid() que está destinada a ser utilizada para esto.
1 |
|
2 |
// generate unique string
|
3 |
echo uniqid(); |
4 |
/* prints
|
5 |
4bd67c947233e
|
6 |
*/
|
7 |
|
8 |
// generate another unique string
|
9 |
echo uniqid(); |
10 |
/* prints
|
11 |
4bd67c9472340
|
12 |
*/
|
Puede notar que aunque las cadenas son únicas, parecen similares por los primeros caracteres. Esto se debe a que la cadena generada está relacionada con la hora del servidor. Esto realmente tiene un buen efecto secundario, ya que cada nuevo ID generado viene más tarde en orden alfabético, por lo que se pueden ordenar.
Para reducir las posibilidades de obtener un duplicado, puede pasar un prefijo o el segundo parámetro para aumentar la entropía:
1 |
|
2 |
// with prefix
|
3 |
echo uniqid('foo_'); |
4 |
/* prints
|
5 |
foo_4bd67d6cd8b8f
|
6 |
*/
|
7 |
|
8 |
// with more entropy
|
9 |
echo uniqid('',true); |
10 |
/* prints
|
11 |
4bd67d6cd8b926.12135106
|
12 |
*/
|
13 |
|
14 |
// both
|
15 |
echo uniqid('bar_',true); |
16 |
/* prints
|
17 |
bar_4bd67da367b650.43684647
|
18 |
*/
|
Esta función generará cadenas más cortas que md5(), lo que también le ahorrará algo de espacio.
7. Serialización
¿Alguna vez ha necesitado almacenar una variable compleja en una base de datos o un archivo de texto? No tiene que encontrar una solución elegante para convertir sus arrays u objetos en cadenas formateadas, ya que PHP ya tiene funciones para este propósito.
Hay dos métodos populares de serialización de variables. He aquí un ejemplo que utiliza serialize() y unserialize():
1 |
|
2 |
// a complex array
|
3 |
$myvar = array( |
4 |
'hello', |
5 |
42, |
6 |
array(1,'two'), |
7 |
'apple'
|
8 |
);
|
9 |
|
10 |
// convert to a string
|
11 |
$string = serialize($myvar); |
12 |
|
13 |
echo $string; |
14 |
/* prints
|
15 |
a:4:{i:0;s:5:"hello";i:1;i:42;i:2;a:2:{i:0;i:1;i:1;s:3:"two";}i:3;s:5:"apple";}
|
16 |
*/
|
17 |
|
18 |
// you can reproduce the original variable
|
19 |
$newvar = unserialize($string); |
20 |
|
21 |
print_r($newvar); |
22 |
/* prints
|
23 |
Array
|
24 |
(
|
25 |
[0] => hello
|
26 |
[1] => 42
|
27 |
[2] => Array
|
28 |
(
|
29 |
[0] => 1
|
30 |
[1] => two
|
31 |
)
|
32 |
|
33 |
[3] => apple
|
34 |
)
|
35 |
*/
|
Este fue el método de serialización PHP nativo. Sin embargo, desde que JSON se ha vuelto tan popular en los últimos años, decidieron añadir compatibilidad con PHP 5.2. Ahora también puede usar las funciones json_encode() y json_decode():
1 |
|
2 |
// a complex array
|
3 |
$myvar = array( |
4 |
'hello', |
5 |
42, |
6 |
array(1,'two'), |
7 |
'apple'
|
8 |
);
|
9 |
|
10 |
// convert to a string
|
11 |
$string = json_encode($myvar); |
12 |
|
13 |
echo $string; |
14 |
/* prints
|
15 |
["hello",42,[1,"two"],"apple"]
|
16 |
*/
|
17 |
|
18 |
// you can reproduce the original variable
|
19 |
$newvar = json_decode($string); |
20 |
|
21 |
print_r($newvar); |
22 |
/* prints
|
23 |
Array
|
24 |
(
|
25 |
[0] => hello
|
26 |
[1] => 42
|
27 |
[2] => Array
|
28 |
(
|
29 |
[0] => 1
|
30 |
[1] => two
|
31 |
)
|
32 |
|
33 |
[3] => apple
|
34 |
)
|
35 |
*/
|
Es más compacto, y lo mejor de todo, compatible con javascript y muchos otros lenguajes. Sin embargo, para objetos complejos, se puede perder alguna información.
8. Compresión de Cadenas de Texto
Al hablar de compresión, por lo general pensamos en archivos, como archivos ZIP. Es posible comprimir cadenas largas en PHP, sin involucrar archivos comprimidos.
En el siguiente ejemplo vamos a utilizar las funciones gzcompress() y gzuncompress():
1 |
|
2 |
$string = |
3 |
"Lorem ipsum dolor sit amet, consectetur
|
4 |
adipiscing elit. Nunc ut elit id mi ultricies
|
5 |
adipiscing. Nulla facilisi. Praesent pulvinar,
|
6 |
sapien vel feugiat vestibulum, nulla dui pretium orci,
|
7 |
non ultricies elit lacus quis ante. Lorem ipsum dolor
|
8 |
sit amet, consectetur adipiscing elit. Aliquam
|
9 |
pretium ullamcorper urna quis iaculis. Etiam ac massa
|
10 |
sed turpis tempor luctus. Curabitur sed nibh eu elit
|
11 |
mollis congue. Praesent ipsum diam, consectetur vitae
|
12 |
ornare a, aliquam a nunc. In id magna pellentesque
|
13 |
tellus posuere adipiscing. Sed non mi metus, at lacinia
|
14 |
augue. Sed magna nisi, ornare in mollis in, mollis
|
15 |
sed nunc. Etiam at justo in leo congue mollis.
|
16 |
Nullam in neque eget metus hendrerit scelerisque
|
17 |
eu non enim. Ut malesuada lacus eu nulla bibendum
|
18 |
id euismod urna sodales. "; |
19 |
|
20 |
$compressed = gzcompress($string); |
21 |
|
22 |
echo "Original size: ". strlen($string)."\n"; |
23 |
/* prints
|
24 |
Original size: 800
|
25 |
*/
|
26 |
|
27 |
|
28 |
|
29 |
echo "Compressed size: ". strlen($compressed)."\n"; |
30 |
/* prints
|
31 |
Compressed size: 418
|
32 |
*/
|
33 |
|
34 |
// getting it back
|
35 |
$original = gzuncompress($compressed); |
Pudimos alcanzar casi el 50% de reducción de tamaño. También las funciones gzencode() y gzdecode() tienen resultados similares, utilizando un algoritmo de compresión diferente.
9. Función de Cierre de Registro
Hay una función llamada register_shutdown_function(), que le permitirá ejecutar algún código justo antes de que el script termine de ejecutarse.
Imagine que desea capturar algunas estadísticas de referencia al final de la ejecución del script, como cuánto tardó en ejecutarse:
1 |
|
2 |
// capture the start time
|
3 |
$start_time = microtime(true); |
4 |
|
5 |
// do some stuff
|
6 |
// ...
|
7 |
|
8 |
// display how long the script took
|
9 |
echo "execution took: ". |
10 |
(microtime(true) - $start_time). |
11 |
" seconds."; |
Al principio esto puede parecer trivial. Sólo agregue el código al final de la secuencia de comandos y se ejecuta antes de que finalice. Sin embargo, si alguna vez llama a la función exit(), ese código nunca se ejecutará. Además, si hay un error fatal, o si el script es terminado por el usuario (presionando el botón Detener en el navegador), de nuevo puede no ejecutarse.
Cuando utiliza register_shutdown_function(), su código se ejecutará sin importar por qué el script ha dejado de ejecutarse:
1 |
|
2 |
$start_time = microtime(true); |
3 |
|
4 |
register_shutdown_function('my_shutdown'); |
5 |
|
6 |
// do some stuff
|
7 |
// ...
|
8 |
|
9 |
|
10 |
function my_shutdown() { |
11 |
global $start_time; |
12 |
|
13 |
echo "execution took: ". |
14 |
(microtime(true) - $start_time). |
15 |
" seconds."; |
16 |
}
|
Conclusión
¿Está al tanto de otras funciones de PHP que no son ampliamente conocidas pero que pueden ser muy útiles? Por favor, comparta con nosotros en los comentarios. ¡Y gracias por leer!



