CakeFest 2017 NYC, the Official CakePHP Conference

Nuevas características

Declaraciones de tipo escalar

Las declaraciones de tipo escalar son de dos tipos: coercitivo (por defecto) y estricto. Ahora se pueden forzar los siguientes tipos para parámetros (tanto coercitiva como estrictamente): cadenas de caracteres (string), números enteros (int), números decimales (float), y booleanos (bool). Estos se añaden a los tipos introducidos en PHP 5: nombres de clases, interfaces, arrays y callables.

<?php
// Modo coercitivo
function sumaDeEnteros(int ...$enteros)
{
    return 
array_sum($enteros);
}

var_dump(sumaDeEnteros(2'3'4.1));

El resultado del ejemplo sería:

int(9)

Para habilitar el modo estricto se debe colocar una simple directiva declare al inicio del fichero. Esto siginfica que la rigurosidad de la tipificación de escalares se configura en función de cada fichero. Esta directiva no solamente afecta a las declaraciones de tipo de parámetros, sino también al tipo de devolución de una función (véanse las declaraciones de tipo de devolución), a funciones internas de PHP, y a funciones de extensiones cargadas.

Se puede encontrar la documentación completa y ejemplos de las declaraciones de tipo escalar en la referencia de declaraciones de tipo.

Declaraciones de tipo de devolución

PHP 7 añade soporte para declaraciones de tipo de devolución. Similarmente a las declaraciones de tipo de argumento, las declaraciones de tipo de devolución especifican el tipo del valor que será devuelto por una función. Están disponibles los mismos tipos tanto para las declaraciones de tipo de devolución como para las declaraciones de tipo de argumento.

<?php

function sumarArrays(array ...$arrays): array
{
    return 
array_map(function(array $array): int {
        return 
array_sum($array);
    }, 
$arrays);
}

print_r(sumarArrays([1,2,3], [4,5,6], [7,8,9]));

El resultado del ejemplo sería:

Array
(
    [0] => 6
    [1] => 15
    [2] => 24
)

Se puede encontrar la documentación completa y ejemplos de las declaraciones de tipo de devolución en la referencia de las declaraciones de tipo de devolución.

Operador de fusión de null

El operador de fusión de null (??) se ha añadido como aliciente sintáctico para el caso común de la necesidad de utilizar un operador ternario junto con isset(). Devuelve su primer operando si existe y no es NULL; de lo contrario devuelve su segundo operando.

<?php
// Obntener el valor de $_GET['usuario'] y devolver 'nadie'
// si no existe.
$nombre_usuario $_GET['usuario'] ?? 'nadie';
// Esto equivale a:
$nombre_usuario = isset($_GET['usuario']) ? $_GET['usuario'] : 'nadie';

// La fusión se puede encadenar: esto devolverá el primer
// valor definido de $_GET['usuario'], $_POST['usuario'],
// y 'nadie'.
$nombre_usuario $_GET['usuario'] ?? $_POST['usuario'] ?? 'nadie';
?>

El operador nave espacial

El operador nave espacial se emplea para comparar dos expresiones. Devuelve -1, 0 o 1 cuando $a es respectivamente menor, igual, o mayor que $b. Las comparaciones se realizan según las reglas de comparación de tipos usuales de PHP.

<?php
// Números enteros
echo <=> 1// 0
echo <=> 2// -1
echo <=> 1// 1

// Numeros decimales
echo 1.5 <=> 1.5// 0
echo 1.5 <=> 2.5// -1
echo 2.5 <=> 1.5// 1
 
// Cadenas de caracteres
echo "a" <=> "a"// 0
echo "a" <=> "b"// -1
echo "b" <=> "a"// 1
?>

Arrays constantes con define()

Ahora se pueden definir constantes de array con define(). En PHP 5.6, solamente se podían definir con const.

<?php
define
('ANIMALES', [
    
'perro',
    
'gato',
    
'pájaro'
]);

echo 
ANIMALES[1]; // imprime "gato"
?>

Clases anónimas

Se ha añadido soporte para clases anónimas mediante new clase. Estas se pueden utilizar en lugar de definiciones de clases completas para objetos desechables:

<?php
interface Logger {
    public function 
log(string $msg);
}

class 
Application {
    private 
$logger;

    public function 
getLogger(): Logger {
         return 
$this->logger;
    }

    public function 
setLogger(Logger $logger) {
         
$this->logger $logger;
    }
}

$app = new Application;
$app->setLogger(new class implements Logger {
    public function 
log(string $msg) {
        echo 
$msg;
    }
});

var_dump($app->getLogger());
?>

El resultado del ejemplo sería:

object(class@anonymous)#2 (0) {
}

La documentación completa se puede encontrar en la referencia de clases anónimas.

Sintaxis de escape de puntos de códigos de Unicode

Esta sintaxis toma un punto de código de Unicode en forma hexadecimal, e imprime ese punto de código en UTF-8 a un string con entrecomillado doble o a un heredoc. Se acepta cualquier punto de código válido, siendo los ceros iniciales opcionales.

echo "\u{aa}";
echo "\u{0000aa}";
echo "\u{9999}";

El resultado del ejemplo sería:

ª
ª (lo mismo que antes pero con ceros iniciales opcinales)
香

Closure::call()

Closure::call() es una manera más eficiente y abreviada de vincular temporalmente un ámbito de objeto a una clausura e invocarla.

<?php
class {private $x 1;}

// Código anterior a PHP
$getXCB = function() {return $this->x;};
$getX $getXCB->bindTo(new A'A'); // clausura intermedia
echo $getX();

// Código de PHP 7+
$getX = function() {return $this->x;};
echo 
$getX->call(new A);

El resultado del ejemplo sería:

1
1

Filtros para unserialize()

Esta característica busca el proporcionar una mejor seguridad al deserializar objetos en datos no fiables. Previene de posibles inyecciones de código al capacitar al desarrollador a crear listas blancas de clases que deden ser deserializadas.

<?php

// convertir todos los objetos a un objeto __PHP_Incomplete_Class
$data unserialize($foo, ["allowed_classes" => false]);

// convertir todos los objetos a un objeto __PHP_Incomplete_Class excepto a los de MiClase y MiClase2
$data unserialize($foo, ["allowed_classes" => ["MiClase""MiClase2"]]);

// comportamiento predeterminado (lo mismo que omitir el segundo argumento) que acepta todas las clases
$data unserialize($foo, ["allowed_classes" => true]);

IntlChar

La nueva clase IntlChar busca exponer funcionalidad adicional de ICU. La clase en sí define varios métodos estáticos y constantes que se pueden emplear para manipular caracteres Unicode.

<?php

printf
('%x'IntlChar::CODEPOINT_MAX);
echo 
IntlChar::charName('@');
var_dump(IntlChar::ispunct('!'));

El resultado del ejemplo sería:

10ffff
COMMERCIAL AT
bool(true)

Para utilizar esta clase debe estar instalada la extensión Intl.

Previsiones

Las previsiones son una mejora retrocompatible con la antigua función assert(). Con ellas se pueden realizar afirmaciones sin coste en código de producción, proporcionando la capacidad de lanzar excepciones personalizadas cuando la afirmación falla.

Mientras que la API antigua se siguie manteniendo por compatibilidad, assert() ahora es un constructor de lenguaje, permitiendo que el primer parámetro sea una expresión en lugar de solamente un string a evaluar o un valor de tipo boolean a probar.

<?php
ini_set
('assert.exception'1);

class 
ErrorPersonalizado extends AssertionError {}

assert(false, new ErrorPersonalizado('Un mensaje de error'));
?>

El resultado del ejemplo sería:

Fatal error: Uncaught ErrorPersonalizado: Un mensaje de error

Se pueden encontrar los detalles completos de esta característica, incluyendo cómo configurarla tanto en entornos de desarrollo como de producción, en la sección de previsiones de la referencia de assert().

Declaraciones de use en grupo

Las clases, funciones y constantes que se importen desde el mismo namespace ahora pueden ser agrupadas en una única sentencia use.

<?php
// Código anterior a PHP 7
use un\espacioDeNombres\ClaseA;
use 
un\espacioDeNombres\ClaseB;
use 
un\espacioDeNombres\ClaseC as C;

use function 
un\espacioDeNombres\fn_a;
use function 
un\espacioDeNombres\fn_b;
use function 
un\espacioDeNombres\fn_c;

use const 
un\espacioDeNombres\ConstA;
use const 
un\espacioDeNombres\ConstB;
use const 
un\espacioDeNombres\ConstC;

// código de PHP 7+
use un\espacioDeNombres\{ClaseAClaseBClaseC as C};
use function 
un\espacioDeNombres\{fn_afn_bfn_c};
use const 
un\espacioDeNombres\{ConstAConstBConstC};
?>

Expresiones 'return' en generadores

Esta característica se basa en la funcionalidad de los generadores introducida en PHP 5.5. Habilita a la sentencia return para utilizarla dentro de un generador para que pueda devolver una expresión final (la devolución por referencia no está permitida). Este valor se puede obtener empleando el nuevo método Generator::getReturn(), el cual solamente se puede utilizar una vez que el generador ha finalizado de producir valores.

<?php

$gen 
= (function() {
    
yield 1;
    
yield 2;

    return 
3;
})();

foreach (
$gen as $val) {
    echo 
$valPHP_EOL;
}

echo 
$gen->getReturn(), PHP_EOL;

El resultado del ejemplo sería:

1
2
3

La capacidad de devolver explícitamente un valor final desde un generador (quizá desde una forma de computación de corutina) es útil debido a que puede ser específicamente manejado por el código del cliente que ejecuta el generador. Esto es mucho más simple que forzar al código del cliente a comprobar primero si el valor final se ha generado y luego, si es asi, manejar dicho valor específicamente.

Delegación de generadores

Los generadores ahora pueden delegar a otro generador, objeto Traversable o array de forma automática, sin la necesidad de escribir «clichés» en el generador más externo con la construcción yield from.

<?php
function gen()
{
    
yield 1;
    
yield 2;
    
yield from gen2();
}

function 
gen2()
{
    
yield 3;
    
yield 4;
}

foreach (
gen() as $val)
{
    echo 
$valPHP_EOL;
}
?>

El resultado del ejemplo sería:

1
2
3
4

División entera con intdiv()

La nueva función intdiv() realiza una división entera de sus operandos y la devuelve.

<?php
var_dump
(intdiv(103));
?>

El resultado del ejemplo sería:

int(3)

Opciones de sesión

session_start() ahora acepta un array de opciones que sobrescriben las directivas de configuración de sesiones establecidas normalmente en php.ini.

Estas opciones también se han ampliado para admitir session.lazy_write, la cual está activada de forma predeterminada y causa que PHP solamente sobrescriba cualquier fichero de sesión si los datos de sesión han cambiado, y read_and_close, la cual es una opción que se puede pasar solo a session_start() para indicar que los datos de sesión deberían ser leídos y luego la sesión debería ser cerrada inmediatamente sin cambios.

Por ejemplo, para establecer session.cache_limiter a private e inmediatamente cerrar la sesión después de leerla:

<?php
session_start
([
    
'cache_limiter' => 'private',
    
'read_and_close' => true,
]);
?>

preg_replace_callback_array()

Con la nueva función preg_replace_callback_array(), el código escrito es más claro al emplear la función preg_replace_callback(). Antes de PHP 7, las retrollamadas que necesitaban ser ejecutadas por cada expresión regular requerían que la función de retrollamda fuera contaminada con muchas ramificaciones.

Ahora, las retrollamadas se pueden registrar para cada expresión regular usando un array asociativo, donde la clave es una expresión regular y el valor es una retrollamada.

Funciones de CSPRNG

Se han añadido dos nuevas funciones para generar números enteros y cadenas de caractéres criptográficamente seguros de una forma multiplataforma: random_bytes() y random_int().

list() siempre desempaqueta objetos que implementen ArrayAccess

Anteriormente, no se garantizaba que list() operase correctamente con objetos que implementasen ArrayAccess. Esto ha sido arreglado.

Otras características

  • Se ha añadido el acceso a miembros de clase al clonar, p.ej. (clone $foo)->bar().
add a note add a note

User Contributed Notes 3 notes

up
39
PawelD
7 months ago
<?php
class foo { static $bar = 'baz'; }
var_dump('foo'::$bar);
?>

if < php7.0

then we will receive a syntax error, unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM)

but php7 returns string(3) "baz"

I think it's not documented anywhere
up
-4
omarv_r at yahoo dot com
6 months ago
lexx918, It is not working unexpectedly... lets see:

Calling to isset() method for a non existing property ($foo->bar in this case), automatically the magic method __isset() is invoked. So

$a = isset($foo->bar) ?: null; // __isset

is correct.

But when we try to evaluate $foo->bar, we are calling a getter. Because the bar property does not exist, the implicit calling is to magic method __get(). So

$a = $foo->bar ?? null; // __get

is correct too.
up
-19
lexx918 at mail dot ru
6 months ago
Sugar of ternary operator:
<?php
$a
?? 'b'
// allegedly equivalent to
isset($a) ? $a : 'b'
?>
.. in classes working unexpectedly:
<?php
class Foo {
    public function
__get($p) { echo "__get" . PHP_EOL; }
    public function
__isset($p) { echo "__isset" . PHP_EOL; }
}
$foo = new Foo;
$a = isset($foo->bar) ?: null; // __isset
$a = $foo->bar ?? null; // __get
?>
To Top