PHP 8 - experimentando novos recursos



O PHP 8 já está no estágio de candidato a lançamento, a versão RC 3 foi lançada em 29 de outubro e o lançamento completo está agendado para 26 de novembro. Então é hora de dar uma olhada nos novos recursos que nos aguardam no PHP 8. O cronograma de lançamento pode ser visto aqui . E o guia oficial para atualização para uma nova versão está aqui .



Adicionado suporte para tipos de união ( RFC )



O tipo de união aceita valores de vários outros tipos, e não apenas um.



<?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;


Adicionado WeakMap ( RFC )



Mapas fracos permitem que você crie relacionamentos entre objetos e valores arbitrários (assim como SplObjectStorage), enquanto os objetos usados ​​como chaves não são protegidos do coletor de lixo. Se o coletor destruir tal objeto, ele será simplesmente removido do mapa.


Este é um recurso muito útil. Isso nos permite pensar ainda menos sobre vazamentos de memória em nosso código. Embora isso não deva ser um problema para a maioria dos desenvolvedores de PHP, vale a pena dar uma olhada ao criar processos de longa execução, por exemplo, usando ReactPHP. Com WeakMaps, as referências de objeto são coletadas automaticamente pelo coletor de lixo quando o objeto se torna indisponível.



Se você fizer o mesmo com uma matriz, as referências do objeto persistirão, levando a um vazamento de memória.



<?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;


Nova exceção ValueError



PHP 8 apresenta uma nova classe de exceção embutida ValueError. Ele se complementa \Exception. O PHP lança essa exceção toda vez que você passa um valor do tipo correto para uma função, mas não pode ser usado nesta operação. Anteriormente, um aviso era emitido nesses casos. Exemplos:



<?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);


Ao definir funções, você pode usar um argumento variável



Qualquer número de parâmetros de função agora pode ser substituído por um argumento variável se seus tipos forem compatíveis. Por exemplo, o código a seguir está incorreto:


<?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 )



O tipo de retorno estático agora pode ser usado para determinar se um método retorna a classe para a qual o método foi chamado, mesmo se ela foi herdada (vinculação estática tardia).



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


Literal de nome de classe de objeto ( RFC )



Agora você pode recuperar o nome da classe de um objeto usando $object::class. O resultado será o mesmo de 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;


Configurações de sintaxe de variável ( RFC )



Newe instanceofagora pode ser usado com expressões arbitrárias: new ()(...$args)e $obj instanceof ().



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


Interface Stringable ( RFC )



O PHP 8 apresenta uma nova interface Stringableque é adicionada automaticamente assim que uma classe implementa um método __toString. Você não precisa implementar explicitamente essa interface.



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


Traits agora podem definir métodos privados abstratos ( RFCs )



<?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;


lance agora pode ser usado como uma expressão ( RFC )



Expressão throwagora pode ser usada onde apenas expressões são permitidas: em funções de seta, operadores de coalescência, operadores ternários condicionais (ternário / elvis).



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


Vírgula suspensa opcional ( RFC ) agora é permitida nos parâmetros da lista



Por analogia com a vírgula suspensa em matrizes, agora você pode defini-la nos parâmetros da 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 exceções sem armazenar em uma variável ( RFC )



Agora você pode escrever catch ()para capturar exceções sem armazená-las em uma variável.



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


Adicionado suporte para o tipo misto ( RFC )



O PHP 8 apresenta um novo tipo chamado misto. Pode ser equivalente aos tipos array, bool, callable, int, float, null, object, resource, string.



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


Adicionado suporte para atributos



Existem várias sugestões para implementar atributos no PHP 8:



  • https://wiki.php.net/rfc/attributes_v2
  • https://wiki.php.net/rfc/attribute_amendments
  • https://wiki.php.net/rfc/shorter_attribute_syntax
  • https://wiki.php.net/rfc/shorter_attribute_syntax_change


Esta é uma das maiores mudanças no PHP 8. Pode não ser fácil descobrir no início. Resumindo, os atributos permitem adicionar metadados a funções, parâmetros, classes, etc. do PHP Esses metadados podem ser recuperados programaticamente. Se no PHP 7 ou inferior você precisar analisar doclocks, os atributos irão ajudá-lo a acessar essas informações profundamente integradas ao próprio PHP.



Para deixar mais claro, imagine que você deseja que seus usuários possam adicionar middleware a uma classe ou controlador de método usando um 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;


Adicionado suporte para encaminhar propriedades do construtor ( RFC )



Propõe-se adicionar uma sintaxe simples para combinar construtor com definição de propriedade:



<?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;


Adicionado suporte para a expressão de correspondência ( RFC )



Propõe-se adicionar uma nova expressão matchque seja semelhante switch, apenas com uma semântica mais segura e a capacidade de retornar valores.



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


Adicionado suporte para o operador nullsafe (? ->) ( RFC )



Quando o resultado do lado esquerdo do operador é nulo, a execução de toda a cadeia é interrompida e seu resultado é definido como nulo. Caso contrário, a cadeia se comporta como um operador normal ->.


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


Adicionado suporte para argumentos nomeados ( RFCs )



A nomenclatura permite que você passe argumentos para uma função com base no nome do parâmetro, não em sua posição. Ou seja, os valores dos argumentos se tornam autodocumentáveis ​​e os argumentos não dependem mais da ordem de enumeração, portanto, você pode ignorar arbitrariamente os valores padrão.


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



All Articles