PHP Desarrollo. Symfony Console Component - Trucos y consejos
Este artículo fue creado con el objetivo de mostrarte los consejos y trucos más útiles y recuperables sobre el desarrollo de la consola Symfony.
La nueva versión de PHP está a la vuelta de la esquina. ¿Cuáles son las nuevas implementaciones que debe conocer? Consulte este artículo para saberlo.
PHP 8.2 está a punto de salir al mercado. Quizá sea la versión que haga que la actualización a PHP 8 resulte atractiva para todo el mundo. Hablemos de lo que los desarrolladores pueden esperar con PHP 8,2 y prepararnos para su última versión. Pero antes, repasemos rápidamente todas las versiones y cambios del PHP a lo largo de los años.
<?php
clase Usuario {
public int $id;
public string $name;
}
?>
<?php
$factor = 10;
$nums = array_map(fn($n) => $n * $factor, [1, 2, 3, 4]);
// $nums = array(10, 20, 30, 40);
?>
<?php
clase A {}
class B extends A {}
clase Productor {
función pública method(): A {}
}
class HijoProductor extends Productor {
public function método(): B {}
}
?>
<?php
$array['clave'] ??= computeDefault();
// equivale aproximadamente a
if (!isset($array['clave'])) {
$array['clave'] = computeDefault();
}
?>
<?php
$parts = ['manzana', 'pera'];
$fruits = ['plátano', 'naranja', ...$parts, 'sandía'];
// ['plátano', 'naranja', 'manzana', 'pera', 'sandía'];
?>
<?php
// Devuelve array que contiene todo el estado necesario del objeto.
public function __serialize(): array;
// Restaura el estado del objeto a partir del array de datos dado.
public function __unserialize(array $data): void;
?>
Lanzado en noviembre de 2020, PHP 8.0 nos trajo las mejores características hasta la fecha, que incluye:
htmlspecialchars($string, double_encode: false);
clase PostsController
{
#[Route("/api/posts/{id}", methods: ["GET"])]
public function get($id) { /* ... */ }
}
clase Punto {
función pública __construct(
public float $x = 0,0,
public float $y = 0,0,
public float $z = 0.0,
) {}
}
clase Número {
función pública __construct(
private int|float $number
) {}
}
new Number('NaN'); // TypeError
echo match (8.0) {
8.0 => "¡Oh, no!",
8.0 => "Esto es lo que esperaba",
};
//> Esto es lo que esperaba
$country = $session?->user?->getAddress()?->country;
enum Estado
{
case Borrador;
case Publicado
caso Archivado;
}
function acceptStatus(Status $status) {...}
clase BlogData
{
public readonly Estado $status;
public function __construct(Estado $status)
{
$this->status = $status;
}
}
$foo = $this->foo(...);
$fn = strlen(...);
clase Servicio
{
privado Logger $logger;
función pública __construct(
Logger $logger = new NullLogger(),
) {
$this->logger = $logger;
}
}
function count_and_iterate(Iterator&Countable $value) {
foreach ($value as $val) {
echo $val;
}
count($value);
}
$response = $httpClient->request('https://example.com/');
print json_decode($response->getBody()->buffer())['code'];
PHP 8,2 introduce más cambios destinados a facilitar la vida del desarrollador y optimizar aún más su trabajo. A continuación se muestra la lista de nuevas características.
Una de las mayores mejoras de la nueva versión de PHP es la posibilidad de crear directamente un sólo lectura
clase. Una clase descrita con esta característica la propagará automáticamente para sus variables. Las clases DTO tendrán ahora un aspecto limpio y ordenado.
readonly class FacturaDTO
{
función pública __construct(
public UUID $uuid,
public Emisor $issuer,
public DateTime $issuedAt,
) {}
}
El segundo gran cambio es la desaprobación de las variables dinámicas en las clases. La siguiente implementación lanzará una deprecación en PHP 8,2 y ErrorException
en la futura versión del PHP.
clase MiUsuario
{
public string $name;
}
(...)
$myUser->nombre = 'Nombre'; // OK
$myUser->surname = 'Apellido'; // obsoleto / errorexception
Cabe mencionar que las clases que implementan __get
y __set
métodos y clases que heredan directamente de stdClass
puede seguir aplicando métodos mágicos sin ningún obstáculo.
Aquí también le remito a un hilo interesante en GitHubdonde los desarrolladores de PHP-CS discuten este cambio y la necesidad de modificar su popular herramienta para la nueva versión del lenguaje.
Por último, pero no menos importante, puede desactivar este comportamiento a través de Anotación.
#[PermitirPropiedadesDinámicas]
clase MiUsuario
{
public string $nombre;
}
$myUser->surname = 'Apellido'; // OK
null
, verdadero
y falso
Hasta ahora, las funciones que siempre devolvían un verdadero
o falso
debía describirse con un bool
tipo.
function alwaysTrue(): bool { return true; }
A partir de ahora, podemos utilizar verdadero
y falso
como tipos simples en los valores devueltos por las funciones.
function alwaysTrue(): true { return true; }
(DNF) es una forma estándar de organizar expresiones booleanas. Específicamente, significa estructurar una expresión booleana en una serie ORed de ANDs. Cuando se aplica a declaraciones de tipos, permite una forma estándar de escribir tipos combinados de Unión e Intersección que el analizador sintáctico puede manejar.
Es un gran cambio, ya que ahora podemos tener tipos de intersección anulables, por ejemplo:
function getFullName((HasName&HasSurname)|null $user) { ... }
No soy un gran defensor del uso de Traits y tal cambio es puramente cosmético para mí, sobre todo porque no le permite utilizar valores Trait sin inicializar el objeto.
trait Foo {
public const FLAG_1 = 1;
protected const FLAG_2 = 2;
private const FLAG_3 = 2;
public function doFoo(int $flags): void {
if ($flags & self::FLAG_1) {
echo 'Tengo bandera 1';
}
if ($flags & self::FLAG_2) {
echo 'Got flag 2';
}
if ($flags & self::FLAG_3) {
echo 'Got flag 3';
}
}
}
Uno de los cambios más importantes que estoy esperando. En la última versión de PHP podremos marcar variables como SensitiveParameterValue
. ¿Por qué?
Las trazas de pila de PHP en las excepciones son muy útiles para la depuración, sin embargo, permiten previsualizar los valores de los parámetros. Por ejemplo, imaginemos que PDO código utilizado para conectarse a una base de datos. La traza de depuración tendría el siguiente aspecto:
PDOException: SQLSTATE[HY000] [2002] No existe tal archivo o directorio en /var/www/html/test.php:3
Seguimiento de pila:
#0 /var/www/html/test.php(3): PDO->__construct('mysql:host=loca...', 'root', 'password')
#1 {main}
Después de utilizar Anotación #[ParámetroSensible]
nuestro seguimiento de pila ya no mostrará el valor de la variable.
función test(
$foo,
#[SensitiveParameter] $bar,
$baz
) {
throw new Exception('Error');
}
test('foo', 'bar', 'baz');
/*
Fatal error: Uncaught Exception: Error en test.php:8
Seguimiento de pila:
#0 test.php(11): test('foo', Object(SensitiveParameterValue), 'baz')
#1 {main}
thrown in test.php on line 8
*/
En El autor dice
La principal motivación para este cambio es permitir la obtención de las propiedades nombre y valor en lugares donde los objetos enum no están permitidos, como las claves de los arrays. Podríamos trabajar en los arrays y extenderlos para permitir enums o todos los objetos como claves, pero permitir obtener propiedades de enums es más sencillo.
enum A: cadena {
case B = 'B';
const C = [self::B->valor => self::B];
}
Antes, los métodos estáticos funcionaban así:
DateTime::createFromImmutable(): DateTime
DateTimeImmutable::createFromMutable(): DateTimeImmutable
En PHP 8,2 se va a cambiar a:
DateTime::createFromImmutable(): static
DateTimeImmutable::createFromMutable(): static
Se trata de un cambio de última hora para los creadores de bibliotecas y/o todas las implementaciones personalizadas de DateTime.
Eran dos funciones que no servían para nada, ya que sólo convertían entre ISO-8859-1
y UTF-8
. PHP Manual sugerimos utilizar mb_convert_encoding
en su lugar.
El autor de la RFC es quien mejor describe la sensibilidad regional:
Antes de PHP 8.0, la configuración regional de PHP se establecía desde el entorno. Cuando un usuario instala Linux, éste le pregunta en qué idioma quiere que esté. Es posible que el usuario no aprecie plenamente las consecuencias de esta decisión. No sólo establece el idioma de la interfaz de usuario para los comandos incorporados, sino que también cambia de forma generalizada cómo funciona el manejo de cadenas en la biblioteca C. Por ejemplo, un usuario que seleccionara "turco" al instalar Linux se encontraría con que las aplicaciones que llamaran a toupper('i') obtendrían la I mayúscula con puntos (U+0130, "İ").
En una era de protocolos estandarizados basados en texto, el lenguaje natural es una aplicación minoritaria para la conversión de mayúsculas y minúsculas. Pero incluso si el usuario quisiera la conversión de mayúsculas y minúsculas en lenguaje natural, sería poco probable que tuviera éxito con strtolower(). Esto se debe a que procesa la cadena byte a byte, alimentando cada byte a la función tolower() de la biblioteca C. Si la entrada es UTF-8, con mucho la opción moderna más popular, strtolower() manipulará la cadena, produciendo típicamente UTF-8 inválido como salida.
PHP 8.0 dejó de respetar las variables de entorno locale. Así que la configuración regional es siempre "C" a menos que el usuario llame explícitamente a setlocale(). Esto significa que la mayor parte del cambio retrocompatible ya ha quedado atrás. Cualquier aplicación que dependa de la configuración regional del sistema para hacer la conversión de mayúsculas y minúsculas de los conjuntos de caracteres de 8 bits heredados se habrá roto con PHP 8.0.
Esto significa que todas las funciones siguientes realizarán la conversión de mayúsculas y minúsculas ASCII a partir de PHP.8.2:strtolower
, strtoupper
, stristr
, stripos
, strripos
, lcfirst
, ucfirst
, ucwords
, str_ireplace
En PHP tenemos muchas formas de incrustar variables en cadenas:
- Incrustación directa de variables ("$foo")
- Corchetes fuera de la variable ("{$foo}")
- Paréntesis después del signo del dólar ("${foo}")
- Variables variables ("${expr}", equivalente a (cadena) ${expr})
Para evitar confusiones y usos indebidos, estos ya no funcionarán:
"Hola ${world}";
En desuso: El uso de ${} en cadenas está obsoleto.
"Hola ${(mundo)}";
Obsoleto: El uso de ${} (variables variables) en cadenas está obsoleto
Estos no son todos los cambios que PHP 8,2 nos ofrecerá. Desafortunadamente, todavía no conseguimos soporte para tipos genéricos, de acuerdo con lo que dijo Nikita los genéricos monomorfizados añadirían demasiada sobrecarga de rendimiento, y los genéricos reificados requieren muchos cambios en toda la base de código. Sin embargo, lo que sí se nota es la disciplina y la visión del producto. Los cambios introducidos en las sucesivas versiones de la lengua son cada vez más claros, y los interesados observarán que PHP avanza en la dirección correcta, tanto en el ámbito de la simplificación sintáctica como en el de la compatibilidad con novedades. Espero que ya el año que viene veamos Llamable
como tipo válido.