¡A partir del 6 de diciembre de 2018, la última y mejor versión, PHP 7.3 ya está aquí! Con él vienen nuevas funciones útiles, funcionalidades, desaprobaciones, un buen número de correcciones de errores y un aumento en el rendimiento. PHP 7.3 ahora también está disponible para todos los clientes de Kinsta en MyKinsta. 🤘

Actualización: PHP 8.1 (versión oficial) ya está disponible para todos los clientes de Kinsta. PHP 7.3 ya no está soportado por Kinsta. Ten en cuenta que soportamos las versiones de PHP 8.0, 8.1, 8.2 y 8.3.

En este articulo, ofreceremos una vista a todas las características y cambios que nosotros consideramos relevantes. Pero siempre puede checar la lista completa de características, cambios y arreglos de bugs en las notas de actualización de PHP 7.3 y peticiones para comentarios de PHP 7.3.

¿Qué Hay de Nuevo en PHP con PHP 7.3?

En este articulo cubriremos los siguientes cambios de PHP 7.3:

Sintaxis Flexibles Heredoc y Nowdoc

Esto es probablemente una de las mejoras más relevantes que vienen con PHP 7.3, y creemos que esto merece un poco más de atención. Así que, antes de adentrarnos a los cambios de heredoc/nowdoc 7.3, les brindaremos una vista rápida de esta función principal y útil. Si ya tiene experiencia con nowdoc y heredoc, será mejor que se salte a la parte con los cambios de PHP 7.3.

Una vista de las sintaxis heredoc y nowdoc

La sintaxis heredoc brinda una forma de agregar una gran cantidad de texto sin la necesidad de escapar las cosas como las citas dobles. Un Heredoc empieza con <<< seguido por un marcador, y termina con el mismo marcador seguido por un punto y coma. Aquí hay un ejemplo:

print <<<EOT
Heredoc text behaves just like a double-quoted string, without the double quotes.
EOT;

Un nowdoc se comporta como un heredoc, con algunas excepciones:

  • El identificador está encerrado en citas sencillas (<<<'EOT')
  • No se hace análisis dentro del nowdoc

Aquí hay un ejemplo de nowdoc:

print <<<'EOT'
Los Nowdocs son los strings de una sola cita al igual que los heredocs son de citas dobles.
EOT;

Los heredocs y nowdocs comparten las mismas reglas regulando el uso del marcador de cierre:

    1. El marcador de cierre debe empezar en la primera columna de la línea
    2. El marcador debe seguir las mismas reglas de nombre como cualquier otra etiqueta en PHP: sólo debe contener caracteres alfanuméricos y guiones bajose.

El PHP Manual advierte:

“Es muy importante tomar en cuenta que la línea con el identificador no debe contener otros caracteres, a excepción del punto y coma (;). Esto quiere decir especialmente que el identificador puede no estar dirigido, y puede que no haya espacios o pestañas antes o después de un punto y coma. También es importante darse cuenta de que el primer carácter antes del identificador de cierre debe ser una línea nueva como es definida por el sistema local de operación. Este es \n en sistemas UNIX, incluyendo macOS. El delimitador de cierre debe también ser seguido por una nueva línea.”

Sintaxis PHP 7.2 inválida:

class foo {
    public $bar = <<<EOT
    bar
    EOT;
}
// Identifier must not be indented

Sintaxis PHP 7.2 válida:

class foo {
    public $bar = <<<EOT
bar
EOT;
}

Para mantenerlo en corto, en PHP 7.2:

  • El marcador de cierre puede no ser dirigido
  • La línea con el marcador de cierre puede no contener caracteres como espacios o pestañas
  • El primer carácter antes del marcador de cierre debe ser una línea nueva
  • El marcador de cierre debe ser seguido por una línea nueva

Es lo suficientemente claro que las sintaxis heredoc y nowdoc son bastante restrictivas, pero PHP 7.3 puede cambiar esto un poco con las siguientes mejoras.

1. Permitir que el marcador de cierre sea dirigido y que el espacio en blanco principal sea despojado

Con PHP 7.3 nos permiten dirigir al marcador de cierre, y podemos escribir el siguiente código de forma segura:

class foo {
    public $bar = <<<EOT
        bar
    EOT;
}

La dirección del marcador de cierre establece la cantidad de espacio en blanco (o pestañas) que serán despojadas de cada línea del cuerpo. Pero tenga cuidado: el marcador de cierre jamás debe de ser dirigido más allá de cualquier otra línea del cuerpo.

Vea el código de abajo:

class foo {
    public $bar = <<<EOT
    bar
        EOT;
}

El código anterior debería mostrar el siguiente error de análisis gramatical:

 Error gramatical: Nivel de dirección en el cuerpo inválido (esperando por lo menos una dirección ...) en %s en línea %d

Despojar las pestañas y espacios en blanco nos permite agregar dirección al cuerpo del heredoc/nowdoc al mismo nivel del código alrededor, y sin necesidad de espacios en blancos innecesarios, antes de cada línea del cuerpo.

Podemos utilizar pestañas y espacios para dirigir, pero no tenemos permitido mezclarlas. Esto quiere decir que debemos utilizar los mismos caracteres de dirección para el marcador de cierre y cualquier línea del cuerpo. En caso de caracteres con direcciones distintas, esperamos un tipo distinto de error gramatical (dirección inválida).

2. Remover el Requerimiento de la Nueva Línea al Final del Marcador de Cierre

Actualmente, una nueva línea debe seguir el marcador para poder terminar el heredoc/nowdoc. PHP 7.3 cambiaría esto y nos permitiría terminar el heredoc/nowdoc en la misma línea. Aquí hay un ejemplo del RFC:

Sintaxis PHP 7.2 válida:

$values = [<<<END
a
b
c
END
, 'd e f'];

Sintaxis PHP 7.3 válida:

$values = [<<<END
a
b
c
END, 'd e f'];

De cualquier forma, tenga cuidado al elegir el nombre de su marcador porque “ocasionalmente” podrá encontrarse con un error, si esté se parece a una palabra que usted haya usado en el cuerpo del heredoc/nowdoc (lea más sobre esto en el RFC y GitHub).

Ambas propuestas pasaron con más de 2/3 votos.

PHP 7.3 RFC

Recursos Adicionales

Permitir un Trailing Comma en Llamadas de Función

Las comas finales, son comas agregadas a la lista de elementos, parámetros o propiedades y son muy útiles en contextos donde los nuevos valores son agregados frecuentemente porque previenen errores debido a una coma faltante. En PHP las comas finales son permitidas en las matrices, y desde PHP 7.2 están permitidas en espacios de nombre agrupados.

A partir de PHP 7.3, las comas finales serán permitidas en las funciones de declaraciones. Las funciones Variad brindan un ejemplo de contexto donde las comas finales son extremadamente útiles:

foo(
    $bar,
    $baz,
);

Podemos utilizar las comas finales al momento de crear una matriz con compact(), para poder regresar a un string formateado con sprintf(), o cuando unimos una matriz:

$newArray = array_merge(
    $arrayOne,
    $arrayTwo,
    ['foo', 'bar'],
);

También, las comas finales serán útiles para la resolución de problemas (debugging).

var_dump(
    $foo,
    $bar,
    $baz,
);

Y son poderosas con unset() y isset():

unset(
    $foo,
    $bar,
    $baz,
);

isset(
    $foo,
    $bar,
    $baz,
);

Las comas finales también estarán permitidas en llamadas de métodos y documentos adjuntos.

Nota: Este cambio sólo afectará a las llamadas de función. Las sintaxis de declaraciones de función no cambiarán. Además de esto, las comas de pie, las múltiples comas finales y las comas principales no estarán permitidas.

Puede encontrar ejemplos adicionales en la página de RFC. Este RFC fue aprobado con un voto de 30 contra 10.

PHP 7.3 RFC

JSON_THROW_ON_ERROR

Una de las funcionalidades apreciables llegando con PHP 7.3 provee una nueva forma de lidiar con los errores JSON. Esto no es una función principal, pero una adición a la extensión JSON que cambiará el comportamiento del error de json_decode() y json_encode().

Actualmente, json_decode() regresa null en error, pero null también puede ser un resultado válido. Esto puede ser confuso, porque

Sólo es posible saber si ocurrió un error al llamar json_last_error() o json_last_error_msg(), el cual regresa un estado de error global en las formas respectivas de lectura de maquina y de lectura humana. – PHP RFC

json_encode() regresa como FALSE en error. Esto queda más claro porque hay un valor especifico de error. De todas formas, ambas funciones no deberían detener la ejecución del programa durante un error, y tampoco mostrar ni una advertencia.

Habiendo dicho esto, aquí esta la propuesta para el PHP 7.3:

Este RFC en su lugar propone agregar un nuevo valor de opción de flag para json_decode() y json_encode(), JSON_THROW_ON_ERROR. Cuando pase este flag, el comportamiento del error de estas funciones será cambiado. El estado del error global no será tocado, y si ocurre un error que pudiera activarlo, estas funciones en su lugar mostrarán un JsonException con el mensaje y código establecido respectivamente a json_last_error() y json_last_error_msg().

Aquí hay un ejemplo mostrando una forma simple de muestra de un error JSON:

try {
    json_decode("{", false, 512, JSON_THROW_ON_ERROR);
}
catch (\JsonException $exception) {
    echo $exception->getMessage(); // echoes "Syntax error"
}

Mostrar una excepción a partir de un error daría varias ventajas que podrá encontrar listadas en el RFC.

Nota: un parámetro inválido a profundidad pasado a json_decode() muestra una advertencia y regresa como NULL. Este comportamiento no será afectado por JSON_THROW_ON_ERROR. Similarmente, los errores de análisis de parámetro no serán afectadas por JSON_THROW_ON_ERROR y seguirán produciendo advertencias.

Esta propuesta fue aprobada con 23 a 0 votos.

PHP 7.3 RFC

Recursos Adicionales

list() – Asignación de Referencia

¿Qué Significa una Asignación de Referencia?

Considere la siguiente línea:

$b = &$a;

Aquí $b obtiene el valor de $a, pero ese valor no está copiado de $a al $b. En PHP podemos asignar un valor por referencia, queriendo decir que dos variables podrían apuntar a los mismos datos, y cada cambio a cualquier variable afecta a los datos originales. Aquí hay un ejemplo del PHP manual:

<?php
$a = 3;
$b = &$a; // $b is a reference to $a

print "$a\n"; // prints 3
print "$b\n"; // prints 3

Ahora, cambiemos el valor de $a:

$a = 4; // change $a

print "$a\n"; // prints 4
print "$b\n"; // también prints 4, ya que $b es una referencia a $a, que ha sido cambiada

¿Qué Es list() Construct y Cómo Cambia con PHP 7.3?

list() construct puede ser usado para “asignar variables como si estuvieran en una matriz”, pero con list() no nos permiten asignar valores variables por referencia.

PHP 7.3 debería cambiar esto, permitiéndonos asignar variables por referencia también con list() construct, como se muestra en el siguiente ejemplo:

$array = [1, 2];
list($a, &$b) = $array;

Que es el mismo que:

$array = [1, 2];
$a = $array[0];
$b =& $array[1];

La ventaja de esta propuesta es que podríamos asignar múltiples variables por referencia, la cual no estaba permitida actualmente. Puede encontrar más ejemplos en el RFC. Esta propuesta pasó con 17 contra 7 votos.

PHP 7.3 RFC

Recursos Adicionales

La función is_countable

Otra característica útil que pronto llegará con PHP 7.3 es la función is_countable(). Hasta PHP 7.2, obtenemos un error al intentar usar count() con algo que no puede ser contable. Por esta razón, para poder evitar una advertencia, nos vemos forzados en tener que agregar el siguiente código:

if (is_array($foo) || $foo instanceof Countable) {
    // $foo is countable
}

Este RFC propone la función is_countable(), la cual regresa true si la variable dada es una matriz o es una variable contable, de otra forma será false. Así que, el código anterior puede ser cambiado de esta forma:

if (is_countable($foo)) {
    // $foo is countable
}

La propuesta pasó con 25 / 0 votos.

PHP 7.3 RFC

Recursos Adicionales

array_key_first(), array_key_last()

Actualmente, podemos extraer la primera y última llave de una matriz utilizando funciones reset(), end() y key(). Desafortunadamente, con estas funciones, no hay forma de obtener el primero o el último índice de una matriz sin cambiar el estado interno. Otras opciones usualmente reducen el código de legibilidad y desempeño.
Esta propuesta podría cambiar este escenario al agregar dos nuevas funciones al PHP core:

  • array_key_first()
  • array_key_last()

A partir de PHP 7.3, array_key_first() y array_key_last()permiten extraer la primera y última llave de cualquier matriz sin afectar el apuntador de la matriz interna. Estas nuevas funciones nos permitirían escribir código mucho menos complejo y en algunos casos evitar errores. Vea el RFC para obtener más información y varios ejemplos.

array_key_first() y array_key_last() han sido aprobados con 18 contra 14 votos.

Nota: el RFC original propuso dos funciones extras,array_value_first() y array_value_last(), los cuales fueron votados en una encuesta distinta, pero no han sido aprobados y no formarán parte del PHP core.

PHP 7.3 RFC

Recursos Adicionales

Mejoras de Contraseña Hash Argon2

Argon2 es un algoritmo de hash implementado en PHP 7.2 como una alternativa al algoritmo Bcrypt. PHP 7.2 introduce la constante PASSWORD_ARGON2I, disponible para ser usada en funciones password_*:

password_hash('password', PASSWORD_ARGON2I);

Desde su primera implementación, una nueva variante de Argon2 ha sido agregada, así que, a partir de que se escribió este articulo, Argon2 viene con tres variantes:

  • Argon2d maximiza la resistencia a los ataques de cracking de GPU. Es más rápido y utiliza datos dependiendo del acceso a la memoria.
  • Argon2i utiliza acceso a memoria de datos independientes, que es preferible para contraseñas hash. Es más lento ya que hace más pasos sobre la memoria para protegerla de ataques de intercambio.
  • Argon2id es una versión híbrida que combina el enfoque de Argon2i para el primer paso sobre la memoria, y el enfoque Argon2d para pasos subsecuentes.

Argon2id es recomendado en el internet, a excepción de cuando hayan buenas razones para preferir de forma especifica otra variante.

El nuevo RFC propone la implementación de Argon2id dentro de las password_* funciones con la nueva constante PASSWORD_ARGON2ID:

password_hash('password', PASSWORD_ARGON2ID);

La implementación es idéntica a la implementación Argon2i, y aceptará los mismos factores de costo:

  • Un costo de memoria el cual define el número de KiB que deben ser consumido durante el hashing (los valores por defecto son 1<<10, o 1024 KiB, o 1MiB)
  • Un costo de tiempo que define el número de iteraciones del algoritmo de hashing (por defecto a 2)
  • Un factor de paralelismo, el cual establece el número de hilos paralelos que serán usados durante el hashing (por defecto 2)

Vea el siguiente código:

$options = ['memory_cost' => 1<<11, 'time_cost' => 4, 'threads' => 2];
password_hash('password', PASSWORD_ARGON2ID, $options);

Más información y ejemplos en el RFC.

PHP 7.3 RFC

Recursos Adicionales

Deprecaciones

Las siguientes funciones/funcionalidades serán depreciadas con PHP 7.3 y removidas no más allá de PHP 8.0.

Deprecar y Remover image2wbmp()

La función image2wbmp() saca o guarda una versión WBMP de una imagen. Esta función toma tres argumentos: un recurso de imagen, un nombre de archivo (el camino al archivo guardado), y un color en primer plano.
Desde PHP 5.0, es idéntico a imagewbmp(), así que este RFC propone depreciarlo y removerlo. Desde PHP 7.3, cada llamada a image2wbmp()emitiría una advertencia de depreciación. Después de ser removida, cada llamada mostraría un error fatal.

PHP 7.3 RFC

Deprecar y remover constantes que no distinguen entre minúsculas y mayúsculas

PHP actualmente soporta a constantes que son sensibles a las minúsculas y mayúsculas, como también a las constantes que no lo son. De cualquier forma, las constantes insensibles están soportadas, pero normalmente tienen inconsistencias en las funcionalidades y pueden ser complejas de usar.
Esta propuesta comienza con las siguientes premisas:

  • Las class constants siempre son sensibles
  • Las constantes globales declaradas con const siempre son sensibles
  • Las constantes definidas con define() son sensibles por defecto

Además de esto, la Referencia de Lenguaje de PHP explícitamente declara:

Un constante es sensible a las mayúsculas y minúsculas por defecto. Por conveniencia identificadores constantes son de mayúsculas.

Habiendo dicho esto este RFC propone los siguientes cambios:

  • Llamadas de depreciación define() con un tercer parámetro establecido a true – PHP 7.3
  • Constantes sensibles de acceso deprecante con una cubierta distinta de la declaración con excepción de true, false and null) – PHP 7.3
  • Eliminar la posibilidad para declarar constantes insensibles – PHP 8.0
  • Convierte true, false y null de constantes con cubierta especial en palabras clave reservadas – PHP 8.0

PHP 7.3 RFC

Depreciar y Remover Constantes Insensibles a las minúsculas y mayúsculas.

Deprecaciones Adicionales para PHP 7.3

Aquí hay una lista rápida de funcionalidades depreciadas en PHP 7.3. no es exhaustiva, simplemente son propuestas de depreciación que personalmente considero más relevantes. Para una lista completa de deprecaciones propuestas, vea Deprecaciones para PHP 7.3.

Alias de función mbstring sin documentar: hay un número de alias de función sin documentar de mbstring que son duplicados de funciones equivalentes utilizando el mb_ prefix. Por ejemplo, mbereg es un alias de mb_ereg.
Todas estas funciones serán marcadas como depreciadas y unas notificaciones de depreciación será lanzada cuando sean encontradas durante la compilación.

Funciones de búsqueda de string con una aguja entera. Estas funciones usualmente operan sobre agujas de string. Si una aguja sin string es brindada, esta es convertida en un entero y es aplicada como el valor ordinal de un carácter (lea más sobre esto en el manual de PHP). Aquí tenemos un ejemplo de RFC:

$str = "There are 10 apples";
var_dump(strpos($str, "10")); // int(10)
var_dump(strpos($str, 10));   // bool(false)

Esto es confuso y causa problemas impredecibles porque el tipo puede cambiar con la fuente de los datos de usuario. Por esta razón, el RFC propone la emisión de una emergencia de depreciación si una aguja sin string es pasada a una de las siguientes funciones:

  • strpos
  • strrpos
  • stripos
  • strripos
  • strstr
  • strchr
  • strrchr
  • stristr

En PHP 8.0, la advertencia de depreciación debe ser removida y las agujas deben ser convertidas de forma automática en strings.

fgetss() La función string.strip_tags y filtro de flujo : fgetss() y string.strip_tags remueve etiquetas de un flujo mientras lo va leyendo. Ambas funciones y el filtro exponen la funcionalidad strip_tags() haciendo la implementación del strip_tags() algo más completo, ya que una maquina de estado de flujo es requerida. Adicionalmente, el RFC resalta otro inconveniente de estas funciones:

Por un lado, estas funciones pueden lucir poco útiles. strip_tags() por sí misma, debido a sus limitaciones y bugs conocidos, tiene muy pocas aplicaciones legitimas. No hay razón para proveer un soporte nativo para la aplicación de streaming además de todo esto.

Así que el RFC propone marcar fgetss(), gzgetss() y SplFileObject::fgetss() como deprecados.

¿Qué Significa PHP 7.2 para los Usuarios de WordPress?

Según la página de estadísticas oficial de WordPress, al tiempo de escribir esto sólo el 32.9% de usuarios de WordPress han actualizado a PHP 7. Y sólo el 4% utiliza PHP 7.2. Como puede ver una gran mayoría de los usuarios, más del 38%, siguen ejecutando en PHP 5.6. Lo que es aún más atterador es que más del 28.5% de los usuarios utilizan versiones de PHP no soportadas. A partir de diciembre de 2016, WordPress.org realmente destacó su recomendación oficial para usuarios de PHP 5.6 a PHP 7 o superior.

Estadísticas de WordPress PHP
Estadísticas de WordPress PHP

Rendimiento de PHP 7

Los números anteriores son especialmente desalentadores desde el punto de vista del rendimiento, ya que PHP 7 ha demostrado ser significativamente más rápido. Aquí son unas estadísticas:

  • Puntos de referencia oficiales de PHP muestran ques PHP 7 permite que el sistema ejecute el doble de solicitudes por segundo en comparación con PHP 5.6, a casi la mitad de la latencia.
  • Christian Vigh también publicó una comparación de rendimiento de PHP que demostró que PHP 5.2 ers 400% más lento que PHP 7.

Hemos ejecutado nuestras propias pruebas de rendimiento. Similarmente a los rendimientos de arriba hemos visto que WordPress 5.0 en PHP 7.3 podía ejecutar casi 3 veces más transacciones (solicitudes) por segundo que PHP 5.6.

Rendimiento de WordPress
Rendimiento de WordPress
  • WordPress 5.0 PHP 5.6 resultado de rendimiento: 91.64 sol/seg
  • WordPress 5.0 PHP 7.0 resultado de rendimiento: 206.71 sol/seg
  • WordPress 5.0 PHP 7.1 resultado de rendimiento: 210.98 sol/seg
  • WordPress 5.0 PHP 7.2 resultado de rendimiento: 229.18 sol/seg
  • WordPress 5.0 PHP 7.3 resultado de rendimiento: 253.20 sol/seg 🏆

También es interesante notar que WordPress 4.9.8 en PHP 7.3 fue ligeramente más rápido que WordPress 5.0.

WordPress 4.9.8
WordPress 4.9.8
  • WordPress 4.9.8 PHP 5.6 resultado de rendimiento: 97.59 sol/seg
  • WordPress 4.9.8 PHP 7.0 resultado de rendimiento: 221.42 sol/seg
  • WordPress 4.9.8 PHP 7.1 resultado de rendimiento: 233.78 sol/seg
  • WordPress 4.9.8 PHP 7.2 resultado de rendimiento: 250.36 sol/seg 
  • WordPress 4.9.8 PHP 7.3 resultado de rendimiento: 276.31 sol/seg 🏆

Muchos tardan en actualizarse simplemente por el tiempo que lleva probar nuevos plugins y temas de terceros para garantizar que funcionen correctamente. Pero muchas veces, todo se reduce a que simplemente no lo han hecho todavía.

Comprobando tu versión de PHP

¿No está seguro de qué versión de PHP está ejecutando? Una de las maneras más fáciles de averiguarlo es usar una herramienta como Pingdom o Google Chrome Devtools. El primer encabezado de solicitud HTTP generalmente le mostrará la versión.

Verifique la versión de PHP
Verifique la versión de PHP

Esto se basa en que el host no modifique el valor del encabezado X-Powered-By. Si lo hacen, es posible que no vea su versión de PHP. En cuyo caso, también puede instalar un plugin gratuito como Version Info que le mostrará información básica del servidor en el pie de página de su panel de administración de WordPress.

Verificar versiones de PHP en WordPress
Verificar versiones de PHP en WordPress

Alternativamente, también puede cargar un archivo vía FTP para ver su versión de PHP, o comunicarse con su host y preguntar.

Actualizar a PHP 7.3

Una vez PHP 7.2 salga puede comenzar a probar. Puede probar su sitio de WordPress localmente o verificar sus scripts en un entorno como Docker, que le permite probar diferentes versiones de PHP desde la línea de comandos.

O puede utilizar un entorno de staging, ya que se parecerá más a un sitio de producción en vivo. Puede fácilmente crear un entorno de staging con un solo clic.

Pruebe en un entorno de staging
Pruebe en un entorno de staging

Siempre recomendamos realizar pruebas exhaustivas antes de utilizarlo en un sitio de producción. Para hacerlo, simplemente cambie la versión de PHP para el sitio de staging en “Herramientas” y puede comenzar las pruebas para asegurar la compatibilidad de sus plugins y temas de terceros.

Cambio a PHP 7.3 RC 4
Cambio a PHP 7.3 RC 4

Una vez que confirme que todo está en orden, puede cambiar su sitio de producción a PHP 7.3 o si había modificado algo puede pasar a producción su sitio de prueba.

Resumen

La última y mejor versión de PHP está aquí. Nos traen regalos como heredocs flexibles y nowdocs, comas finales en llamadas a funciones, list() asignaciones de referencia y más. En esta publicación, proporcionamos una visión general de nuestros mejoras y cambios favoritos, pero también nos gustaría saber cuáles son sus favoritos y en qué formas los aprovechará. Háganos saber en la sección de comentarios a continuación. ¡Y no olvide que PHP no está muerto!

Puede encontrar la lista completa de propuestas de PHP 7.3 en la páginas Peticiones por Comentarios y en las Notas de Actualización de PHP 7.3 en GitHub.

Carlo Daniele Kinsta

Carlo es un diseñador y desarrollador de front-end freelance. Cuando escribe artículos y tutoriales, Carlo se ocupa principalmente de los estándares web, pero cuando juega con sitios web, su mejor compañero de trabajo es WordPress.