PHP 8: probando nuevas funciones



PHP 8 ya se encuentra en la etapa de candidato de lanzamiento, la versión RC 3 se lanzó el 29 de octubre y el lanzamiento completo está programado para el 26 de noviembre. Así que es hora de echar un vistazo a las nuevas funciones que nos esperan en PHP 8. El calendario de lanzamiento se puede ver aquí . Y la guía oficial para actualizar a una nueva versión está aquí .



Soporte agregado para tipos de unión ( RFC )



El tipo de unión acepta valores de varios otros tipos, no solo uno.



<?php
declare(strict_types=1);
 
class Number {
    private int|float $number;
 
    public function setNumber(int|float $number): void {
        $this->number = $number;
    }
 
    public function getNumber(): int|float {
        return $this->number;
    }
}
 
/**
 * We can pass both floats or integer values
 * to the number object. Try passing a string.
 */
$number = new Number();
 
$number->setNumber(5);
 
dump($number->getNumber());
 
$number->setNumber(11.54);
 
dump($number->getNumber());
 
exit;


WeakMap agregado ( RFC )



Los mapas débiles le permiten crear relaciones entre objetos y valores arbitrarios (así como SplObjectStorage), mientras que los objetos utilizados como claves no están protegidos del recolector de basura. Si el coleccionista destruye tal objeto, simplemente se elimina del mapa.


Esta es una caracteristica muy útil. Nos permite pensar aún menos en las pérdidas de memoria en nuestro código. Si bien esto no debería ser un problema para la mayoría de los desarrolladores de PHP, vale la pena analizarlo al crear procesos de larga ejecución, por ejemplo, usando ReactPHP. Con WeakMaps, el recolector de basura recopila automáticamente las referencias a objetos cuando el objeto deja de estar disponible.



Si hace lo mismo con una matriz, las referencias a objetos persistirán, lo que provocará una pérdida de memoria.



<?php
declare(strict_types=1);
 
class FooBar {
    public WeakMap $cache;
    
    public function __construct() {
      $this->cache = new WeakMap();
    }
 
    public function getSomethingWithCaching(object $obj) {
        return $this->cache[$obj] ??= $this->computeSomethingExpensive($obj);
    }
    
    public function computeSomethingExpensive(object $obj) {
    dump("I got called");
    return rand(1, 100);
    }
}
 
$cacheObject = new stdClass;
 
$obj = new FooBar;
// "I got called" only will be printed once
$obj->getSomethingWithCaching($cacheObject);
$obj->getSomethingWithCaching($cacheObject);
 
dump(count($obj->cache));
 
// When unsetting our object, the WeakMap frees up memory
unset($cacheObject);
 
dump(count($obj->cache));
 
exit;


Nueva excepción ValueError



PHP 8 introduce una nueva clase de excepción incorporada ValueError. Se complementa a sí mismo \Exception. PHP lanza esta excepción cada vez que pasa un valor del tipo correcto a una función, pero no se puede usar en esta operación. Previamente, se emitió una advertencia en tales casos. Ejemplos:



<?php
declare(strict_types=1);
 
/**
 * We pass an array to array_rand,
 * which is of the correct type. But
 * array_rand expects non-empty arrays.
 *
 * This throws a ValueError exception.
 */
array_rand([], 0);
 
/**
 * The depth argument for json_decode is a
 * valid integer, but it must be greater than 0
 */
json_decode('{}', true, -1);


Al definir funciones, puede utilizar un argumento variado



Ahora se puede reemplazar cualquier número de parámetros de función con un argumento variádico si sus tipos son compatibles. Por ejemplo, el siguiente código es incorrecto:


<?php
declare(strict_types=1);
 
class A {
    public function method(int $many, string $parameters, $here) {
 
    }
}
class B extends A {
    public function method(...$everything) {
        dd($everything);
    }
}
 
$b = new B();
$b->method('i can be overwritten!');
exit;


Tipo de retorno estático ( RFC )



El tipo de retorno estático ahora se puede usar para determinar si un método devuelve la clase para la que se llamó al método, incluso si fue heredado (enlace estático tardío).



<?php
declare(strict_types=1);
 
class Test {
    public function doWhatever(): static {
        // Do whatever.
        return $this;
    }
}
 
exit;


Nombre de clase de objeto literal ( RFC )



Ahora puede recuperar el nombre de clase de un objeto usando $object::class. El resultado será el mismo que con get_class($object).



<?php
declare(strict_types=1);
 
auth()->loginUsingId(1);
 
dump(auth()->user()::class);
 
// Or with a temporary variable
$user = auth()->user();
 
dump($user::class);
exit;


Configuración de sintaxis variable ( RFC )



Newy instanceofahora se puede usar con expresiones arbitrarias: new ()(...$args)y $obj instanceof ().



<?php
declare(strict_types=1);
 
class Foo {}
class Bar {}
 
 
$class = new (collect(['Foo', 'Bar'])->random());
 
dd($class);
 
exit;


Interfaz encadenable ( RFC )



PHP 8 introduce una nueva interfaz Stringableque se agrega automáticamente tan pronto como una clase implementa un método __toString. No es necesario implementar explícitamente esta interfaz.



<?php
declare(strict_types=1);
 
class Foo {
    public function __toString() {
        return 'I am a class';
    }
}
 
$obj = new Foo;
dump($obj instanceof Stringable);
 
exit;


Los rasgos ahora pueden definir métodos privados abstractos ( RFC )



<?php
declare(strict_types=1);
 
 
trait MyTrait {
    abstract private function neededByTheTrait(): string;
 
    public function doSomething() {
        return strlen($this->neededByTheTrait());
    }
}
 
class TraitUser {
    use MyTrait;
 
    // This is allowed:
    private function neededByTheTrait(): string { }
 
    // This is forbidden (incorrect return type)
    // private function neededByTheTrait(): stdClass { }
 
    // This is forbidden (non-static changed to static)
    // private static function neededByTheTrait(): string { }
}
 
exit;


throw ahora se puede usar como una expresión ( RFC )



La expresión throwahora se puede usar donde solo se permiten expresiones: en funciones de flecha, operadores de unión, operadores condicionales ternarios (ternario / elvis).



<?php
declare(strict_types=1);
 
$callable = fn() => throw new Exception();
 
$nullableValue = null;
 
// $value is non-nullable.
$value = $nullableValue ?? throw new \InvalidArgumentException();
 
 
exit;


La coma colgante opcional ( RFC ) ahora está permitida en los parámetros de la lista



Por analogía con la coma colgante en las matrices, ahora puede definirla en los parámetros de la lista.



<?php
declare(strict_types=1);
 
function method_with_many_arguments(
    $a, 
    $b,
    $c,
    $d,
) {
    dump("this is valid syntax");
}
 
method_with_many_arguments(
    1,
    2,
    3,
    4,
);
 
exit;


Captura de excepciones sin almacenar en una variable ( RFC )



Ahora puede escribir catch ()para detectar excepciones sin almacenarlas en una variable.



<?php
declare(strict_types=1);
 
$nullableValue = null;
 
try {
    $value = $nullableValue ?? throw new \InvalidArgumentException();
} catch (\InvalidArgumentException) {
    dump("Something went wrong");
}
 
 
exit;


Soporte agregado para tipo mixto ( RFC )



PHP 8 introduce un nuevo tipo llamado mixto. Puede ser equivalente a los tipos array, bool, invocable, int, float, null, object, resource, string.



<?php
declare(strict_types=1);
 
function debug_function(mixed ...$data) {
    dump($data);
}
 
debug_function(1, 'string', []);
 
exit;


Soporte agregado para atributos



Hay varias sugerencias para implementar atributos en PHP 8:





Este es uno de los mayores cambios en PHP 8. Puede que no sea tan fácil de entender al principio. En resumen, los atributos le permiten agregar metadatos a funciones, parámetros, clases, etc. de PHP. Luego, estos metadatos se pueden recuperar mediante programación. Si en PHP 7 o versiones anteriores necesitas analizar doclocks, los atributos te ayudarán a acceder a esta información, profundamente integrada en PHP.



Para hacerlo más claro, imagine que desea que sus usuarios puedan agregar middleware a un controlador de clase o método mediante un atributo.



<?php
declare(strict_types=1);
// First, we need to define the attribute. An Attribute itself is just a plain PHP class, that is annotated as an Attribute itself.
 
#[Attribute]
class ApplyMiddleware
{
    public array $middleware = [];
 
    public function __construct(...$middleware) {
        $this->middleware = $middleware;
    }
}
 
// This adds the attribute to the MyController class, with the "auth" middleware as an argument.
 
#[ApplyMiddleware('auth')]
class MyController
{
    public function index() {}
}
 
// We can then retrieve all ApplyMiddleware attributes on our class using reflection
// And read the given middleware arguments.
 
$reflectionClass = new ReflectionClass(MyController::class);
 
$attributes = $reflectionClass->getAttributes(ApplyMiddleware::class);
 
foreach ($attributes as $attribute) {
    $middlewareAttribute = $attribute->newInstance();
    dump($middlewareAttribute->middleware);
}
 
exit;


Se agregó soporte para reenviar las propiedades del constructor ( RFC ).



Se propone agregar una sintaxis simple para combinar constructor con definición de propiedad:



<?php
declare(strict_types=1);
 
class User {
    public function __construct(
        public int $id,
        public string $name,
    ) {}
}
 
$user = new User(1, 'Marcel');
 
dump($user->id);
dump($user->name);
 
exit;


Soporte agregado para la expresión de coincidencia ( RFC )



Se propone agregar una nueva expresión match, que es similar switch, solo que con una semántica más segura y la capacidad de devolver valores.



<?php
declare(strict_types=1);
 
echo match (1) {
    0 => 'Foo',
    1 => 'Bar',
    2 => 'Baz',
};
 
exit;


Se agregó soporte para el operador nullsafe (? ->) ( RFC )



Cuando el resultado del lado izquierdo del operador es nulo, se detiene la ejecución de toda la cadena y su resultado se establece en nulo. De lo contrario, la cadena se comporta como un operador normal ->.


<?php
declare(strict_types=1);
 
class User {
    public function getAddress() {}
}
 
$user = new User();
 
$country = $user?->getAddress()?->country?->iso_code;
 
dump($country);
 
exit;


Se agregó soporte para argumentos con nombre ( RFC )



La denominación le permite pasar argumentos a una función en función del nombre del parámetro, no de su posición. Es decir, los valores de los argumentos se autodocumentan y los argumentos ya no dependen del orden de enumeración, por lo que puede omitir arbitrariamente los valores predeterminados.


<?php
declare(strict_types=1);
 
array_fill(start_index: 0, num: 100, value: 50);
 
exit;



All Articles