Mostrando entradas con la etiqueta PHP. Mostrar todas las entradas
Mostrando entradas con la etiqueta PHP. Mostrar todas las entradas

Los cambios en el lenguaje de PHP 5.5

ETIQUETA ,

Los cambios en el lenguaje de PHP 5.5

Al margen de la nueva API para codificar contraseñas, de la nueva extensión OPcache y de losnuevos generadores PHP, la versión 5.5 de PHP incluye varias novedades en el propio lenguaje. A continuación se explican las cinco novedades más importantes.

Accediendo a elementos de arrays y caracteres de cadenas

PHP 5.5 permite acceder de forma directa a los elementos de un array y a los caracteres de una cadena de texto cuando se definen como literales (lo que se conoce en inglés como "array & string dereferencing"):
$amigo = ["amigo1", "amigo2", "amigo3", "amigo4"][1];
// $amigo = "amigo2"
 
$inicial = "Palabra"[0];
// $inicial = 'P'

La propiedad ::class

A partir de PHP 5.5, todas las clases definen una propiedad estática llamada ::class y que devuelve el nombre cualificado completo de la clase. En otras palabras, ::class devuelve el nombre de la clase junto con su namespace completo.
namespace Symfony\Component\HttpFoundation;
 
class Request { ... }
 
$nombreCompleto = Request::class;
// $nombreCompleto = "Symfony\Component\HttpFoundation\Request"

La palabra reservada finally

Los bloques try-catch ahora pueden definir un nuevo bloque de código bajo la nueva palabra clavefinally. El código encerrado dentro de finally se ejecuta siempre, independientemente de las excepciones que se produzcan.
try {
    $total = 0;
    $numProductos = 0;
    $precioMedio = $total / $numProductos;
 
    // ...
} catch (Exception $e) {
    echo "Excepción: ".$e->getMessage();
} finally {
    echo "Este código se ejecuta siempre.";
}
Si no se produce ninguna excepción, la ejecución de la aplicación es la siguiente:
  1. Se ejecuta el código encerrado por el bloque try.
  2. Se ejecuta el código encerrado por el bloque finally.
  3. Se continúa ejecutando el resto de la aplicación.
Si se produce alguna excepción, la aplicación se ejecuta de la siguiente manera:
  1. Se intenta ejecutar el código del bloque try, pero se produce una excepción.
  2. Se ejecuta el código encerrado por el bloque catch definido para la excepción que se ha producido.
  3. Se ejecuta el código definido por el bloque finally.
  4. Se continúa ejecutando el resto de la aplicación o se detiene por completo en función del código ejecutado en el bloque catch anterior.
Los bloques finally son muy útiles por ejemplo para asegurar que la aplicación cierra correctamente los descriptores de archivos (función fclose()) y para cerrar conexiones con las bases de datos (función mysqli_close()):
$db = mysqli_connect();
 
try {
    // hacer consultas a la base de datos
} finally {
    mysqli_close($db);
}

La estructura foreach y la función list()

La estructura de control foreach ahora puede extraer los elementos individuales cuando se recorren arrays de arrays.
Antes de PHP 5.5, esta era la única forma de acceder a los elementos individuales de los arrays interiores:
$productos = [
    ["Nombre 1", "Precio 1", "Descripción 1"],
    ["Nombre 2", "Precio 3", "Descripción 2"],
    ["Nombre 3", "Precio 3", "Descripción 3"]
];
 
foreach ($productos as $producto) {
    $nombre      = $producto[0];
    $precio      = $producto[1];
    $descripcion = $producto[2];
 
    // ...
}
A partir de la versión 5.5, puedes utilizar el siguiente código más conciso y fácil de entender:
$productos = [
    ["Nombre 1", "Precio 1", "Descripción 1"],
    ["Nombre 2", "Precio 3", "Descripción 2"],
    ["Nombre 3", "Precio 3", "Descripción 3"]
];
 
foreach ($productos as list($nombre, $precio, $descripcion)) {
    // ...
}
Si el número de variables de list() es inferior al número de elementos del array, se ignoran los elementos sobrantes del array. Si el número de variables de list() es mayor que el número de elementos de cada array, se muestra un error de tipo Notice: Undefined offset.

La función empty() admite expresiones

La función empty() ahora admite como argumento cualquier tipo de expresión, no sólo variables.
if (empty(function () { return false; })) {
    echo "El valor pasado es vacío.";
}
Recuerda que la función empty() es en realidad un atajo de !isset($var) || $var == false. Por lo tanto, los siguientes valores se consideran vacíos: una cadena de texto vacía, un array sin elementos, una variable declarada pero sin valor, null, false, 0, "0" y 0.0.
Con este cambio, el código de las aplicaciones se puede simplificar al realizar comprobaciones sobre el valor devuelto por las funciones:
// antes de PHP 5.5 había que hacer así las comprobaciones
if (empty($producto = findProducto($productoId))) {
    error('No se ha encontrado el producto');
}
 
// con PHP 5.5 el código anterior se simplifica
if (empty(findProducto($productoId))) {
    error('No se ha encontrado el producto');
}

Auto De Tutorial sowertec16:07

Los generadores de PHP 5.5

ETIQUETA ,

Los generadores de PHP 5.5

Los generadores son una de las novedades más importantes y útiles introducidas por PHP 5.5. Sin embargo, los generadores también son uno de los conceptos más difíciles de entender cuando no estás acostumbrado a trabajar con ellos.
Los generadores simplifican drásticamente la creación de iteradores. Así que antes de explicar los generadores, es importante repasar qué son y para qué sirven los iteradores. Según la definición de la Wikipedia:
"Un iterador es un objeto que permite recorrer los valores almacenados en un contenedor".
Si utilizas por ejemplo la función range() junto con foreach() en tu código, en la práctica estás iterando sobre una lista de valores:
foreach (range(0, 10) as $numero) {
    echo "Número: $numero \n";
}
Si no existiera la función range() deberías crear un iterador a medida capaz de recorrer una serie de números. Para crear un iterador, crea una nueva clase que extienda de la clase Iterator de PHP. Esta clase Iterator define los siguientes cinco métodos abstractos que debes implementar en tu clase:
class Iterator extends Traversable {
    // devuelve el valor del elemento actual dentro de la iteración
    abstract public mixed current();
 
    // devuelve la clave del elemento actual dentro de la iteración
    abstract public scalar key();
 
    // mueve la iteración hasta el siguiente elemento
    abstract public void next();
 
    // mueve la iteración hasta el anterior elemento
    abstract public void rewind();
 
    // comprueba si la posición actual de la iteración es válida
    // (es decir, si el objeto iterador sigue teniendo elementos)
    abstract public boolean valid();
}
PHP ya incluye muchos iteradores útiles como ArrayIterator para recorrer arrays y objetos yRecursiveDirectoryIterator para recorrer de forma recursiva los contenidos de un directorio. Puedes consultar la lista de todos los iteradores que incluye PHP en la página Iteradores del manual oficial de PHP.
Volviendo al ejemplo anterior, como no existe un iterador equivalente a la función range(), deberías crearlo a mano extendiendo de la clase Iterator. A continuación se muestra un posible código de este iterador:
class RangeIterator extends Iterator
{
    public function __construct($primero, $ultimo, $salto)
    {
        $this->primero = $primero;
        $this->ultimo  = $ultimo;
        $this->salto   = $salto;
        $this->actual  = $this->primero;
    }
 
    public function current()
    {
        return $this->actual;
    }
 
    public function key()
    {
        return $this->actual;
    }
 
    public function next()
    {
        $this->actual += $this->salto;
    }
 
    public function rewind()
    {
        $this->actual = $this->primero;
    }
 
    public function valid()
    {
        return ($this->actual >= $this->primero)
            && ($this->actual <= $this->ultimo);
    }
}
Como demuestra claramente el código del ejemplo anterior, crear un iterador es algo aburrido y muy costoso. Los generadores son la solución a este problema, ya que tienen funcionalidades similares a los iteradores y cuestan mucho menos crearlos.
Observa el siguiente ejemplo que muestra el código de un generador equivalente a la función range()de PHP y por tanto, equivalente al iterador RangeIterator creado anteriormente:
function genera_numeros($primero, $ultimo, $salto = 1) {
    for ($numero = $primero; $numero <= $ultimo; $numero += $salto) {
        yield $numero;
    }
}
 
foreach (genera_numeros(0, 10) as $numero) {
    echo "Número: $numero \n";
}
Técnicamente, un generador es muy parecido a una función. La principal diferencia es que en vez de usar la palabra reservada return para devolver un valor, el generador utiliza la palabra reservadayield para devolver uno a uno todos sus valores.
Si la función genera_numero() anterior fuese normal, debería crear un array con todos los números y después devolverlos con la instrucción return $numeros;. Sin embargo, al utilizar yield en vez dereturn, la función se convierte en un generador. Cuando se ejecute, este generador devuelve un número cada vez, hasta que se cumpla la condición que hace detenerse al generador.
¿Qué sucede si la aplicación necesita 1 millón de números? Con la función normal que genera todos los números y los guarda en un array que devuelve con return, el consumo de memoría sería de más de 100 MB. Con el generador anterior, sólo se devuelve un número cada vez, por lo que el consumo de memoria se reduce a menos de 1 KB.
La forma en la que un generador devuelve sus resultados es la parte más difícil de entender al empezar a trabajar con generadores. Piensa que una función normal tiene que generar toda su información de una vez antes de devolverla con return. Los generadores, de ahí su nombre, generan la información "al vuelo" a medida que se les solicita y la van devolviendo con yield, que es como unreturn que se puede llamar varias veces sin salirse de la función.
Esto es posible porque cuando se llama a la función del generador, no se ejecuta su código, sino que se devuelve un objeto de la clase Generator. Después, el código del generador se ejecuta paso a paso dentro del foreach.
El resultado devuelto por yield también puede estar compuesto por una clave y un valor, lo que es ideal para simular que se está recorriendo un array asociativo. El siguiente ejemplo muestra un generador que utiliza cURL para realizar peticiones HTTP a las URL indicadas:
function getUrls($urls)
{
    foreach($urls as $url) {
        $curl = curl_init($url);
 
        yield $url => curl_exec($curl);
    }
}
 
foreach(getUrls(array(...)) as $url => $contenido) {
    // ...
}
Los generadores se pueden combinar entre sí (un generador devuelve un valor con yield que a su vez ha obtenido a través de otro generador que también ha utilizado el yield) y también se pueden combinar con los iteradores. El siguiente ejemplo muestra cómo combinar iteradores y generadores para recorrer todos los contenidos de un directorio y si existe algún archivo comprimido, también se muestran sus contenidos:
function recorreArchivoZip($archivoComprimido)
{
    $zip = zip_open($archivoComprimido);
    $elemento = zip_read($zip);
 
    while($elemento !== false) {
        yield $archivoComprimido."/".zip_entry_name($elemento);
    }
 
    zip_close($archivoComprimido);
}
 
function recorreDirectorio($archivos)
{
    foreach($archivos as $archivo) { 
        if(fnmatch('*.zip', $archivo)) {
            foreach(recorreArchivoZip($archivo) as $elemento) {
                yield $elemento;
            }
        } else {
            yield $archivo;
        }
    }
}
 
$dir = new DirectoryIterator("...");
foreach(recorreDirectorio($dir) as $archivo) {
    print $archivo."\n";
}
La principal limitación de los generadores que no se puede controlar su ejecución tal y como sucede en un iterador. Como los iteradores disponen de los métodos next() y rewind(), puedes ir hacia adelante o hacia atrás las veces que necesites. Los generadores no disponen de ese métodorewind() por lo que siempre se ejecutan desde el principio hasta el final y en un único sentido.
Otra limitación de los generadores derivada de su incapacidad para ir hacia atrás es que no puedes ejecutar el mismo generador más de una vez. Si quieres repetir la ejecución, tienes que clonar el generador.

Referencias útiles

El manual oficial de PHP contiene varios artículos interesantes sobre los generadores.
Los ejemplos utilizados en este artículo han sido extraídos de la presentación Looking ahead: PHP 5.5 impartida por David Soria en la conferencia PHP UK 2013.

Auto De Tutorial sowertec16:06

Las nuevas funciones de PHP 5.5

ETIQUETA ,

Las nuevas funciones de PHP 5.5

Nuevas funciones del núcleo de PHP

Una de las nuevas funciones más útiles añadidas por PHP 5.5 es array_column(), que extrae todos los valores de una determinada columna del array multidimensional indicado.
Si utilizas por ejemplo PDO para obtener registros de una base de datos, aunque sólo quieras obtener una columna, el resultado siempre es un array multidimensional:
$resultado = array(
    array('nombre' => 'Usuario 1'),
    array('nombre' => 'Usuario 54'),
    array('nombre' => 'Usuario 231'),
    array('nombre' => 'Usuario 4'),
    // ...
);
Gracias a la nueva función array_column(), resulta muy sencillo aplanar ese array para quedarse solamente con la columna nombre:
$nombres = array_column($resultado, 'nombre');
La función array_column() solamente permite extraer una columna cada vez, pero admite un tercer parámetro opcional que indica la columna cuyos valores se utilizan como claves del nuevo array. Imagina que el array del ejemplo anterior tuviera más columnas de información:
$resultado = array(
    array(
        'id'     => 1,
        'nombre' => 'Usuario 1',
        'edad'   => '...',
    ),
    array(
        'id'     => 54,
        'nombre' => 'Usuario 54',
        'edad'   => '...',
    ),
    array(
        'id'     => 231,
        'nombre' => 'Usuario 231',
        'edad'   => '...',
    ),
    array(
        'id'     => 4,
        'nombre' => 'Usuario 4',
        'edad'   => '...',
    )
);
 
$nombres = array_column($resultado, 'nombre');
$nombresOrdenadosPorId = array_column($resultado, 'nombre', 'id');
El resultado de ejecutar el código anterior sería:
$nombres = array(
    0 => 'Usuario 1',
    1 => 'Usuario 54',
    2 => 'Usuario 231',
    3 => 'Usuario 4',
    // ...
);
 
$nombresOrdenadosPorId = array(
    1   => 'Usuario 1',
    54  => 'Usuario 54',
    231 => 'Usuario 231',
    4   => 'Usuario 4',
    // ...
);
Los valores de la columna que se utiliza como clave no tienen que ser necesariamente numéricos. Si los valores son cadenas de texto, la diferencia será que el array resultante es asociativo en vez de numérico.
La nueva función json_last_error_msg() devuelve el último mensaje de error producido al ejecutar la función json_encode() o json_decode(). Si no se ha producido ningún error, devuelve null.
Las versiones anteriores de PHP incluyen varias funciones para convertir una variable a un tipo determinado: intval(), floatval() y strval(). Ahora PHP 5.5 añade la función que faltaba:boolval(), que convierte cualquier variable en un valor booleano:
boolval(0);             // false
boolval(42);            // true
boolval(0.0);           // false
boolval(4.2);           // true
boolval("");            // false
boolval("string");      // true
boolval([1, 2]);        // true
boolval([]);            // false
boolval(new stdClass);  // true

Nuevas funciones relacionadas con bases de datos

La extensión MySQLi ha añadido tres nuevas funciones relacionadas con las transacciones:
  • mysqli_begin_transaction(), indica que debe empezar una transacción.
  • mysqli_release_savepoint(), deshace los cambios de una transacción y vuelve hasta el punto de guardado que se indica.
  • mysqli_savepoint(), crea un nuevo punto de guardado dentro de una transacción.
Por su parte, la extensión PostgreSQL ha añadido dos nuevas funciones:
  • pg_escape_literal(), aplica el mecanismo de escape a un contenido antes de insertarlo en la base de datos. Se recomienda el uso de esta nueva función en vez de pg_escape_string().
  • pg_escape_identifier(), aplica el mecanismo de escape a una cadena de texto que contiene el nombre de una tabla o de un campo de la base de datos y que va a ser utilizado en una consulta.

Nuevas funciones de la extensión gd

La librería GD utilizada por PHP se ha actualizado a la versión 2.1, lo que añade nuevas funcionalidades, corrige algunos errores y mejora el rendimiento global.
La nueva función imageflip() voltea horizontal o verticalmente una imagen. El primer argumento es la imagen que se manipula y el segundo es una constante que define el tipo de volteo a realizar: horizontal (IMG_FLIP_HORIZONTAL), vertical (IMG_FLIP_VERTICAL) o los dos a la vez (IMG_FLIP_BOTH).
$rutaImagen = 'foto.png';
$imagen = imagecreatefrompng($rutaImagen);
 
// voltearla verticalmente
imageflip($imagen, IMG_FLIP_VERTICAL);
 
// mostrar la imagen en el navegador
imagejpeg($imagen);
imagedestroy($imagen);
Ahora también es posible redimensionar imágenes con la función imagescale(). El primer argumento indica la imagen a redimensionar, el segundo argumento indica la nueva anchura en píxeles, el tercer argumento opcional indica la nueva altura en píxeles y el cuarto argumento opcional indica el tipo de escalado que se aplica:
$imagen = imagecreatefrompng('foto.png');
 
// la nueva anchura de la imagen será 600 píxel
// (la altura se calcula automáticamente para mantener las proporciones)
imagescale($imagen, 600);
 
// la nueva imagen será de 600 x 350 píxeles
// (aunque eso suponga deformar la imagen original)
imagescale($imagen, 600, 350);
 
// el método empleado para redimensionar la imagen será
// el escalado bicúbico, mucho más lento pero de más calidad
// las constantes definidas son:
//   * IMG_NEAREST_NEIGHBOUR
//   * IMG_BILINEAR_FIXED
//   * IMG_BICUBIC
//   * IMG_BICUBIC_FIXED
imagescale($imagen, 600, 350, IMG_BICUBIC);
Recortar imágenes es un requerimiento habitual en las aplicaciones web. La nueva funciónimagecrop() simplifica al máximo esta tarea. Su primer argumento es la imagen a recortar y el segundo argumento es un array asociativo con las claves x, y, width y height que definen el área de corte:
$imagen = imagecreatefrompng('foto.png');
 
imagecrop($imagen, array('x' => 0, 'y' => 0, 'width' => 100, 'height' => 200));
Además de la función imagecrop() PHP 5.5 define una función relacionada llamada imagecropauto()para recortar las imágenes de forma automática. Su primer argumento es la imagen a recortar y el segundo argumento es alguna de las siguientes constantes:IMG_CROP_DEFAULT,IMG_CROP_TRANSPARENT,IMG_CROP_BLACK,IMG_CROP_WHITE y IMG_CROP_SIDES.
$imagen = imagecreatefrompng('foto.png');
 
imagecrop($imagen, IMG_CROP_TRANSPARENT);
imagecrop($imagen, IMG_CROP_SIDES);
Por último, se han añadido otras tres funciones menos importantes: imageaffinematrixconcat(),imageaffinematrixget() y imagepalettetotruecolor(), que convierte una imagen con un número limitado de colores en una imagen de color verdadero.

Nuevas funciones de la extensión curl

La principal función añadida por la extensión cURL es curl_file_create(), que permite crear fácilmente un objeto de tipo CURLFile para subir archivos con el método POST de HTTP. Su primer argumento es la ruta del archivo, el segundo argumento opcional es el tipo MIME del archivo y el tercer parámetro opcional es el nombre con el que se subirá el archivo:
$ch = curl_init('http://librosweb.es/subir_archivo.php');
 
$archivoCurl = curl_file_create('foto.jpg','image/jpeg','otro_nombre');
 
curl_setopt($ch, CURLOPT_POST,1);
curl_setopt($ch, CURLOPT_POSTFIELDS, array('otro_nombre' => $archivoCurl));
 
curl_exec($ch);
Si ejecutas el código del ejemplo anterior, el script que responda la URL subir_archivo.php recibirá un archivo llamado otro_nombre, de tipo JPEG y que contiene la imagen del archivo foto.jpg.
Además de esta función, se han añadido dos funciones complementarias llamadas curl_escape() ycurl_unescape(). La primera codifica una cadena de texto para que sea seguro incluirla como parte de una URL. La segunda hace el proceso inverso para recuperar el contenido original de una cadena de texto codificada como parte de una URL.
Por último, se han añadido otras funciones como curl_pause(), que detiene o continúa la ejecución de las peticiones y curl_reset() que inicializa todas las opciones de la conexión a sus valores por defecto. Para ver el resto de funciones añadidas por cURL consulta el siguiente enlace: New cURL functions.

Nuevas funciones de la extensión socket

La extensión Socket ha definido tres nuevas funciones: socket_sendmsg() para enviar un mensaje a través de un socket, socket_recvmsg() que es la función complementaria para leer los mensajes recibidos a través de un socket y socket_cmsg_space(), que calcula el tamaño que debería reservarse como buffer de mensajes.

Nuevas funciones de la extensión intl

La extensión intl es con diferencia la que más funciones ha añadido en esta nueva versión de PHP. Además, en el momento de escribir este tutorial casi ninguna de esas funciones está documentada. Ver listado de nuevas funciones intl.

Nuevas funciones para la línea de comandos

Si ejecutas scripts de PHP a través de la consola de comandos, ahora puedes establecer el nombre del proceso bajo el que se ejecuta PHP. Este nombre es el que luego aparece al listar los procesos del servidor con comandos como top y ps. Establece el nombre del proceso PHP con la funcióncli_set_process_title() y obtén el nombre del proceso actual con la funcióncli_get_process_title().

Nuevos argumentos para las funciones

Además de añadir nuevas funciones, PHP 5.5 cambia los argumentos de algunas de las funciones existentes.
La función json_encode() ahora admite un tercer parámetro llamado $depth y que indica hasta qué nivel de profundidad (para los arrays) o hasta que nivel de recursividad (para los objetos) se tiene en cuenta para codificar el objeto o array.
Las funciones set_error_handler() y set_exception_handler() ahora admiten el valor null como argumento. En ese caso, devuelven respectivamente el anterior handler para errores y excepciones.
Las funciones de la extensión intl han recibido muchos cambios, que puedes consultar con detalle en el artículo Changed Functions
Por último, la función preg_replace() ya no soporta el modificador /e. Utiliza en su lugar la funciónpreg_replace_callback().

Cambios incompatibles con las versiones anteriores de PHP

Para que su funcionamiento sea más parecido al del lenguaje Perl, se ha modificado el comportamiento de las funciones pack() y unpack().
La función pack() ahora soporta el formato Z, que se comporta igual que el formato a disponible anteriormente.
La función unpack() ha sufrido varios cambios:
  • Ahora soporta el formato Z para las cadenas rellenas con el carácter NULL y se comporta igual que el formato a (elimina todos los bytes NULL sobrantes).
  • Si se utiliza el formato a, se mantienen todos los bytes null sobrantes
  • El formato A ahora eliminar todos los espacios en blanco sobrantes.
El siguiente ejemplo muestra el código que debes utilizar en PHP 5.5 para mantener la retrocompatibilidad de los datos comprimidos con el formato a:
// código válido antes de PHP 5.5
$datos = unpack('a5', $datosComprimidos);
 
// a partir de PHP 5.5 el comportamiento cambia
if (version_compare(PHP_VERSION, '5.5.0-dev', '>=')) {
  $datos = unpack('Z5', $datosComprimidos);
} else {
  $datos = unpack('a5', $datosComprimidos);
}
Por otra parte, se han declarado obsoletas las siguientes cuatro funciones de la extensión Mcrypt:mcrypt_cbc(), mcrypt_cfb(), mcrypt_ecb() y mcrypt_ofb().

Funciones eliminadas

Por su poca utilidad práctica, PHP 5.5 ha eliminado las siguientes cuatro funciones cuyo resultado únicamente servía para mostrar el logotipo de PHP: php_logo_guid(), php_egg_logo_guid(),php_real_logo_guid() y zend_logo_guid().

Auto De Tutorial sowertec16:05

SOWER TEC