Hay mucha información obsoleta en la Web que lleva por mal camino a los nuevos usuarios de PHP, propagando malas prácticas y el código inseguro. PHP: La Manera Correcta es una referencia rápida y fácil de leer, referencia rápida para los estándares de codificación PHP más populares, enlaces a tutoriales autorizados y lo que los colaboradores consideran las mejores prácticas en la actualidad.
No existe una fórmula única para utilizar PHP. Este sitio web pretende introducir a los nuevos desarrolladores de PHP PHP a algunos temas que pueden no descubrir hasta que sea demasiado tarde, y tiene como objetivo dar a los profesionales experimentados algunas ideas frescas sobre los temas que han estado haciendo durante años sin reconsiderarlo nunca. Este sitio web tampoco le dirá qué herramientas utilizar, sino que sino que le sugerirá varias opciones y, cuando sea posible, explicará las diferencias de enfoque y uso.
Este es un documento vivo y seguirá actualizándose con más información útil y ejemplos a medida que estén disponibles. y ejemplos útiles a medida que estén disponibles.
PHP: La Manera Correcta está traducido a muchos idiomas:
La versión más reciente de PHP: La Manera Correcta también está disponible en formato PDF, EPUB y MOBI. Ir a Leanpub
¡Ayude a hacer de este sitio web el mejor recurso para los nuevos programadores de PHP! Contribuir en GitHub
Si se está iniciando en PHP, comience con la versión estable actual de PHP 8.3. PHP 8.x añade muchas características nuevas con respecto a las versiones anteriores 7.x y 5.x. El motor se ha reescrito en gran medida, y PHP es ahora incluso más rápido que las versiones anteriores. PHP 8 es una actualización importante del lenguaje y contiene muchas nuevas funciones y optimizaciones.
Deberías intentar actualizar a la última versión estable rápidamente - PHP 7.4 ya ha llegado al final de su vida útil. Actualizar es fácil, ya que no hay muchas diferencias de compatibilidad con versiones anteriores. PHP 8.0, PHP 8.1, PHP 8.2, PHP 8.3. Si no está seguro de en qué versión se encuentra una función o característica, puede consultar la documentación de PHP en el sitio web php.net.
Con PHP 5.4 o posteriores, puede empezar a aprender PHP sin necesidad de instalar y configurar un servidor web completo. Para iniciar el servidor, ejecute el siguiente comando desde su terminal en la raíz web de su proyecto:
> php -S localhost:8000
macOS 12 (Monterey) y posteriores no vienen preempaquetados con PHP. Las versiones anteriores de macOS incluyen PHP pero no incluyen la última versión estable. Hay varias formas de instalar la última versión de PHP en macOS.
Homebrew es un gestor de paquetes para macOS que te ayuda a instalar fácilmente PHP y varias extensiones. El repositorio central de Homebrew proporciona “fórmulas” para PHP 7.4, 8.0, 8.1, 8.2 y PHP 8.3. Instala la última versión con este comando:
brew install php@8.3
Puede cambiar entre las versiones de PHP de Homebrew modificando su variable PATH
. Alternativamente, puede usar brew-php-switcher para cambiar de versión de PHP automáticamente.
También puede cambiar manualmente entre versiones de PHP desvinculando y vinculando la versión deseada:
brew unlink php
brew link --overwrite php@8.2
brew unlink php
brew link --overwrite php@8.3
El proyecto MacPorts es una iniciativa de código abierto para diseñar un sistema fácil de usar paracompilar, instalar y actualizar software de código abierto basado en línea de comandos, X11 o Aqua en el sistema operativo macOS.
MacPorts soporta binarios pre-compilados, por lo que no necesitas recompilar cada dependencia desde los archivos tarball fuente, esto te salva la vida si no tienes ningún paquete instalado en tu sistema.
En la actualidad, puede instalar php54
, php55
, php56
, php70
, php71
, php72
, php73
, php74
, php80
, php81
, php82
o php83
utilizando el comando port install
, por ejemplo:
sudo port install php74
sudo port install php83
And you can run select
command to switch your active PHP:
sudo port select --set php php83
phpbrew es una herramienta para instalar y gestionar múltiples versiones de PHP. Esto puede ser realmente útil si dos aplicaciones/proyectos requieren diferentes versiones de PHP, y no está utilizando máquinas virtuales.
Otra opción popular es php-osx.liip.ch que proporciona métodos de instalación de una línea para las versiones 5.3 a 7.3. No sobrescribe los binarios PHP instalados por Apple, sino que instala todo en una ubicación separada. (/usr/local/php5).
Otra opción que le da control sobre la versión de PHP que instala, es compilarlo usted mismo. En ese caso asegúrese de tener instalado Xcode o el sustituto de Apple “Command Line Tools for XCode” descargable desde el Centro de Desarrolladores de Apple.
Las soluciones listadas arriba se encargan principalmente del propio PHP, y no suministran cosas como Apache, Nginx o un servidor SQL. Las soluciones “todo en uno” como MAMP y XAMPP instalarán estas otras partes del software por usted y las unirán todas, pero la facilidad de configuración tiene como contrapartida la falta de flexibilidad.
Puede descargar los binarios en windows.php.net/download. Después de la extracción de PHP, se recomienda establecer el PATH a la raíz de su carpeta PHP (donde se encuentra php.exe) para que pueda ejecutar PHP desde cualquier lugar.
Para el aprendizaje y el desarrollo local, puede utilizar el construido en el servidor web con PHP 5.4 + por lo que no necesita preocuparse de configurarlo. Si desea una solución “todo-en-uno” que incluya un servidor web completo y MySQL también entonces herramientas como como XAMPP, EasyPHP, OpenServer y WAMP le ayudará a poner en marcha rápidamente un entorno de desarrollo Windows. Dicho esto, estas herramientas serán un poco diferentes de las de producción, así que ten cuidado con las diferencias de entorno si estás trabajando en Windows y desplegando en Linux.
Si necesita ejecutar su sistema de producción en Windows, IIS7 le proporcionará la mayor estabilidad y el mejor rendimiento. Puedes usar phpmanager (un plugin GUI para IIS7) para que la configuración y gestión de PHP sea más sencilla. IIS7 viene con FastCGI integrado y listo para usar, sólo necesitas configurar PHP como manejador. Para soporte y recursos adicionales existe un área dedicada en iis.net para PHP.
Por lo general, la ejecución de su aplicación en diferentes entornos en el desarrollo y la producción puede dar lugar a errores extraños que aparecen cuando usted va a producción. Si estás desarrollando en Windows y desplegando en Linux (o en cualquier otro sistema que no sea Windows) entonces deberías considerar el uso de una Máquina Virtual.
Chris Tankersley tiene una entrada de blog muy útil sobre qué herramientas utiliza para hacer desarrollo PHP usando Windows.
La mayoría de las distribuciones GNU/Linux vienen con PHP disponible desde los repositorios oficiales, pero esos paquetes usualmente están un poco atrasados con respecto a la versión estable actual. Existen múltiples formas de obtener versiones más recientes de PHP en dichas distribuciones. En las distribuciones GNU/Linux basadas en Ubuntu y Debian, por ejemplo, las mejores alternativas para paquetes nativos las proporcionadas y mantenidas Ondřej Surý, a través de su Archivo Personal de Paquetes (PPA) en Ubuntu y DPA/bikeshed en Debian. Encontrarás las instrucciones para cada uno de ellos más abajo. Dicho esto, siempre puedes usar contenedores, compilar el código fuente PHP, etc.
Para distribuciones Ubuntu, el PPA de Ondřej Surý proporciona versiones de PHP soportadas junto con muchas extensiones PECL. Para añadir este PPA a su sistema, realice los siguientes pasos en su terminal:
En primer lugar, añada el PPA a las fuentes de software de su sistema mediante el comando
sudo add-apt-repository ppa:ondrej/php
Después de añadir el PPA, actualice la lista de paquetes de su sistema:
sudo apt update
Esto asegurará que su sistema pueda acceder e instalar los últimos paquetes PHP disponibles en el PPA.
Para las distribuciones basadas en Debian, Ondřej Surý también proporciona un bikeshed (equivalente en Debian a un PPA). Para añadir el bikeshed a su sistema y actualizarlo, siga estos pasos:
Asegúrese de que tiene acceso de root. Si no es así, es posible que tenga que utilizar sudo
para ejecutar los siguientes comandos.
Actualice la lista de paquetes de su sistema:
sudo apt-get update
Instale lsb-release
, ca-certificates
, y curl
:
sudo apt-get -y install lsb-release ca-certificates curl
Descargue la clave de firma del repositorio:
sudo curl -sSLo /usr/share/keyrings/deb.sury.org-php.gpg https://packages.sury.org/php/apt.gpg
Añada el repositorio a las fuentes de software de su sistema:
sudo sh -c 'echo "deb [signed-by=/usr/share/keyrings/deb.sury.org-php.gpg] https://packages.sury.org/php/ $(lsb_release -sc) main" > /etc/apt/sources.list.d/php.list'
Por último, actualice de nuevo la lista de paquetes de su sistema:
sudo apt-get update
Con estos pasos, su sistema será capaz de instalar los últimos paquetes PHP desde bikeshed.
Una pregunta común entre los que empiezan a escribir programas para la web es: “¿dónde pongo mis archivos?”. A lo largo de los años, la respuesta ha sido consistentemente “donde está el DocumentRoot
”. Aunque esta respuesta no es del todo completa, es un buen punto de partida.
Por razones de seguridad, los archivos de configuración no deben ser accesibles por los visitantes de un sitio; por lo tanto, los scripts públicos se guardan en un directorio público y las configuraciones y datos privados se guardan fuera de ese directorio.
En cada equipo, CMS o framework en el que uno trabaja, cada uno de ellos utiliza una estructura de directorios estándar. Sin embargo, si uno está empezando un proyecto por si mismo, saber qué estructura de sistema de archivos utilizar puede ser intimidante.
Paul M. Jones ha realizado una fantástica investigación sobre las prácticas comunes de decenas de miles de proyectos de github en el ámbito de PHP. Ha compilado una estructura estándar de archivos y directorios, el Standard PHP Package Skeleton, basado en esta investigación. En esta estructura de directorios, DocumentRoot
debe apuntar a public/
, las pruebas unitarias deben estar en el directorio tests/
, y las librerías de terceros, instaladas por composer, deben estar en el directorio vendor/
. Para otros archivos y directorios, seguir el Standard PHP Package Skeleton tendrá más sentido para los contribuidores de un proyecto.
La comunidad PHP es grande y diversa, compuesta por innumerables bibliotecas, frameworks y componentes. Es habitual que los desarrolladores de PHP elijan varios de ellos y los combinen en un único proyecto. Es importante que el código PHP se adhiera (tanto como sea posible) a un estilo de código común para facilitar a los desarrolladores mezclar y combinar varias librerías para sus proyectos.
El Framework Interop Group ha propuesto y aprobado una serie de recomendaciones de estilo. No todas están relacionadas con el estilo del código, pero las que sí lo hacen son PSR-1, PSR-12, PSR-4 y PER Coding Style. Estas recomendaciones no son más que un conjunto de reglas que muchos proyectos como Drupal, Zend, Symfony, Laravel, CakePHP, phpBB, AWS SDK, FuelPHP, Lithium, etc. adoptan. Puedes utilizarlas para tus propios proyectos, o seguir utilizando tu estilo personal.
Lo ideal sería escribir código PHP que se adhiera a un estándar conocido. Esto podría ser cualquier combinación de PSRs, o uno de los estándares de codificación hechos por PEAR o Zend. Esto significa que otros desarrolladores pueden leer y trabajar fácilmente con su código, y las aplicaciones que implementan los componentes pueden tener consistencia incluso cuando se trabaja con mucho código de terceros.
Puedes usar PHP_CodeSniffer para comprobar el código contra cualquiera de estas recomendaciones, y plugins para editores de texto como Sublime Text para recibir feedback en tiempo real.
Puede corregir la estructura del código automáticamente utilizando una de las siguientes herramientas:
Y puedes ejecutar phpcs manualmente desde el shell:
phpcs -sw --standard=PSR1 file.php
Mostrará los errores y describirá cómo solucionarlos.
También puede ser útil incluir el comando phpcs
en un git pre-commit hook con el argumento CLI --filter=GitStaged
.
De este modo, el código que contenga errores contra la norma elegida no podrá entrar en el repositorio hasta que los
errores hayan sido corregidos.
Si tiene PHP_CodeSniffer, puede arreglar los problemas de estructura del código reportados por esta herramienta automáticamente, con PHP Code Beautifier and Fixer.
phpcbf -w --standard=PSR1 file.php
Otra opción es usar el PHP Coding Standards Fixer. Mostrará qué tipo de errores tenía la estructura del código antes de corregirlos.
php-cs-fixer fix -v --rules=@PSR1 file.php
Se prefiere el inglés para todos los nombres de símbolos e infraestructura de códigos. Los comentarios pueden redactarse en cualquier idioma fácilmente legible por todas las partes actuales y futuras que puedan trabajar en el código base.
Por último, un buen recurso complementario para escribir código PHP limpio es Clean Code PHP.
PHP es un lenguaje flexible y dinámico que admite diversas técnicas de programación. A lo largo de los años ha evolucionado de forma espectacular, sobre todo con la incorporación de un sólido modelo orientado a objetos en PHP 5.0 (2004), funciones anónimas y namespaces en PHP 5.3 (2009) y traits en PHP 5.4 (2012).
PHP tiene un conjunto muy completo de características de programación orientada a objetos, incluyendo soporte para clases, clases abstractas, interfaces, herencia, constructores, clonación, excepciones y más.
PHP soporta funciones de primera clase, lo que significa que una función puede ser asignada a una variable. Tanto las funciones definidas por el usuario como las funciones internas pueden referenciarse mediante una variable e invocarse dinámicamente. Las funciones pueden pasarse como argumentos a otras funciones (característica denominada Funciones de orden superior) y las funciones pueden devolver otras funciones.
La recursión, una característica que permite a una función llamarse a sí misma, está soportada por el lenguaje, pero la mayor parte del código PHP se centra en la iteración.
Las nuevas funciones anónimas (con soporte para closures) están presentes desde PHP 5.3 (2009).
PHP 5.4 añadió la capacidad de enlazar closures al ámbito de un objeto y también mejoró el soporte para callables de tal forma que pueden ser usadas indistintamente con funciones anónimas en casi todos los casos.
call_user_func_array()
.PHP soporta varias formas de meta-programación a través de mecanismos como la API Reflection y los Métodos Mágicos.
Hay muchos Métodos Mágicos disponibles tales como __get()
, __set()
, __clone()
, __toString()
, __invoke()
, etc.
que permiten a los desarrolladores conectarse al comportamiento de las clases. Los desarrolladores de Ruby a menudo dicen que PHP carece de method_missing
,
pero esto esta disponible como __call()
y __callStatic()
.
Como se mencionó anteriormente, la comunidad PHP tiene muchos desarrolladores creando mucho código. Esto significa que el código PHP de una biblioteca puede usar el mismo nombre de clase que otra. Cuando ambas bibliotecas son usadas en el mismo espacio de nombres, estas colisionan y causan problemas.
Los espacios de nombres (Namespaces) resuelven este problema. Como se describe en el manual de referencia de PHP, los espacios de nombres pueden compararse con los directorios del sistema operativo que espacian o separan los archivos; dos archivos con el mismo nombre pueden coexistir en directorios separados. Del mismo modo, dos clases PHP con el mismo nombre pueden coexistir en espacios de nombres PHP separados. Así de simple.
Es importante que asigne un espacio de nombres a su código para que pueda ser utilizado por otros desarrolladores sin temor a colisionar con otras bibliotecas.
Una forma recomendada de utilizar los espacios de nombres es la descrita en PSR-4, cuyo objetivo es proporcionar una convención estándar de archivos, clases y espacios de nombres para permitir un código plug-and-play.
En octubre de 2014 el PHP-FIG dejó obsoleto el anterior estándar de autocarga: PSR-0. Tanto PSR-0 como PSR-4 siguen siendo perfectamente utilizables. Este último requiere PHP 5.3, por lo que muchos proyectos que solo usan PHP 5.2 implementan PSR-0.
Si va a utilizar un estándar de autocargador para una nueva aplicación o paquete, considere utilizar PSR-4.
La Biblioteca Estándar de PHP (SPL) viene empaquetada con PHP y proporciona una colección de clases e interfaces. Se compone principalmente de clases de estructura de datos comúnmente necesarias (pila, cola, montón, etc.), e iteradores que pueden recorrer estas estructuras de datos o sus propias clases que implementan interfaces SPL.
PHP fue creado para escribir aplicaciones web, pero también es útil para scripting de programas de interfaz de línea de comandos (CLI). Los programas PHP de línea de comandos pueden ayudar a automatizar tareas comunes como pruebas, despliegue y administración de aplicaciones.
Los programas PHP CLI son poderosos porque puedes usar el código de tu aplicación directamente sin tener que crear y asegurar una web GUI para ella. ¡Solo asegúrate de no poner tus scripts PHP CLI en tu raíz web pública!
Intente ejecutar PHP desde su línea de comandos:
> php -i
La opción -i
imprimirá su configuración PHP igual que la función phpinfo()
.
La opción -a
proporciona un shell interactivo, similar al IRB de ruby o al shell interactivo de python. También existen
de otras útiles opciones de línea de comandos, también.
Escribamos un simple programa CLI “Hola, $nombre”. Para probarlo, crea un archivo llamado hello.php
, como se muestra a continuación.
<?php
if ($argc !== 2) {
echo "Como usar: php hello.php <name>" . PHP_EOL;
exit(1);
}
$name = $argv[1];
echo "Hola, $name" . PHP_EOL;
PHP establece dos variables especiales basadas en los argumentos con los que se ejecuta el script. $argc
es una variable entera
que contiene el conteo de argumentos y $argv
es una variable array que contiene el valor de cada argumento.
El primer argumento es siempre el nombre de su archivo de script PHP, en este caso hello.php
.
La expresión exit()
se utiliza con un número distinto de cero para hacer saber al shell que el comando ha fallado. Los códigos de salida más comunes se pueden encontrar aquí.
Para ejecutar nuestro script, antes visto, desde la línea de comandos:
> php hello.php
Como usar: php hello.php <name>
> php hello.php mundo
Hola, mundo
Una de las herramientas más útiles en el desarrollo de software es un depurador adecuado. Te permite rastrear la ejecución de tu código y monitorizar el contenido de la pila. Xdebug, el depurador de PHP, puede ser utilizado por varios IDEs para proporcionar puntos de interrupción e inspección de pila. También puede permitir a herramientas como PHPUnit y KCacheGrind realizar análisis de cobertura de código y perfilado de código. y perfiles de código.
Si te encuentras en un aprieto, dispuesto a recurrir a var_dump()
/print_r()
, y sigues sin encontrar la solución - quizás necesites usar el depurador.
Instalar Xdebug puede ser complicado, pero una de sus características más importantes es la “Depuración Remota” - si desarrollar código localmente y luego probarlo dentro de una máquina virtual o en otro servidor, la depuración remota es la característica que usted querrá habilitar de inmediato.
Tradicionalmente, usted modificaría su Apache VHost o archivo .htaccess con estos valores:
php_value xdebug.remote_host 192.168.?.?
php_value xdebug.remote_port 9000
El “host remoto” y el “puerto remoto” corresponderán a tu ordenador local y al puerto en el que configures tu IDE para escuchar. Entonces es sólo cuestión de poner tu IDE en modo “escuchar conexiones”, y cargar la URL:
http://your-website.example.com/index.php?XDEBUG_SESSION_START=1
Su IDE interceptará ahora el estado actual mientras se ejecuta el script, permitiéndole establecer puntos de interrupción y explorar los valores en memoria.
Los depuradores gráficos hacen que sea muy fácil recorrer el código, inspeccionar variables y evaluar el código contra el tiempo de ejecución en vivo. Muchos IDEs tienen soporte integrado o basado en plugins para la depuración gráfica con Xdebug. MacGDBp es una GUI de Xdebug gratuita e independiente de código abierto para macOS.
Hay un montón de librerías PHP, frameworks y componentes entre los que elegir. Su proyecto probablemente utilizará varios de ellos - estas son las dependencias del proyecto. Hasta hace poco, PHP no tenía una buena manera de gestionar estas dependencias del proyecto. Incluso si las gestionaba manualmente, aún tenía que preocuparse por los autoloaders. Esto ya no es un problema.
Actualmente existen dos grandes sistemas de gestión de paquetes para PHP - Composer y PEAR. Composer es actualmente el gestor de paquetes más popular para PHP, sin embargo durante mucho tiempo PEAR fue el principal gestor de paquetes en uso. Conocer la historia de PEAR es una buena idea, ya que aún puede encontrar referencias a él aunque nunca lo use.
Composer es el gestor de dependencias recomendado para PHP. Enumera las dependencias de tu proyecto en un archivo composer.json
y,
con unos simples comandos, Composer descargará automáticamente las dependencias de tu proyecto y configurará la carga automática por ti.
Composer es análogo a NPM en el mundo node.js, o Bundler en el mundo Ruby.
Existe una plétora de librerías PHP compatibles con Composer y listas para ser utilizadas en tu proyecto. Estos “paquetes” están listados en Packagist, el repositorio oficial de librerías PHP compatibles con Composer.
La forma más segura de descargar Composer es siguiendo las instrucciones oficiales.
Esto verificará que el instalador no está corrupto o manipulado.
El instalador instala un binario composer.phar
en su directorio de trabajo actual.
Recomendamos instalar Composer globalmente (por ejemplo, una única copia en /usr/local/bin
). Para ello, ejecute este comando a continuación:
mv composer.phar /usr/local/bin/composer
Nota: Si lo anterior falla por los permisos, prefijar con sudo
.
Para ejecutar un Composer instalado localmente se usaría php composer.phar
, globalmente es simplemente composer
.
Para los usuarios de Windows la forma más fácil de empezar a funcionar es utilizar el instalador ComposerSetup, que
realiza una instalación global y configura tu $PATH
para que puedas llamar a composer
desde cualquier directorio en tu línea de comandos.
Composer mantiene un registro de las dependencias de tu proyecto en un archivo llamado composer.json
. Puedes gestionarlo
manualmente si lo deseas, o utilizar el propio Composer. El comando composer require
añade una dependencia del proyecto y si no
tienes un archivo composer.json
, se creará uno. Aquí tienes un ejemplo que añade Twig como dependencia de tu proyecto.
composer require twig/twig:^2.0
Como alternativa, el comando composer init
le guiará a través de la creación de un archivo completo composer.json
para su proyecto.
De cualquier manera, una vez que haya creado su archivo composer.json
puede decirle a Composer que descargue e instale sus dependencias en el directorio vendor/
.
Esto también se aplica a los proyectos que ha descargado que ya proporcionan un archivo composer.json
:
composer install
A continuación, añada esta línea al archivo PHP principal de su aplicación; esto le dirá a PHP que utilice el autocargador (del Inglés “autoloader”) de Composer para las dependencias de su proyecto.
<?php
require 'vendor/autoload.php';
Ahora puedes utilizar las dependencias de tu proyecto y se cargarán automáticamente cuando las necesites.
Composer crea un archivo llamado composer.lock
que almacena la versión exacta de cada paquete que descargó
cuando ejecutó por primera vez composer install
. Si comparte su proyecto con otros,
asegúrese de que el archivo composer.lock
esté incluido, de modo que cuando ejecuten composer install
obtengan
las mismas versiones que usted. Para actualizar sus dependencias, ejecute composer update
. No utilice
composer update
al desplegar, sólo composer install
,
de lo contrario puede terminar con diferentes versiones de paquetes en producción.
Ts muy útil cuando se definen los requisitos de versión de forma flexible. Por ejemplo, un requisito de versión de ~1.8
significa
“cualquier cosa más nueva que 1.8.0
, pero menos que 2.0.x-dev
”. También puede utilizar el comodín *
como en 1.8.*
.
Ahora el comando composer update
de Composer actualizará todas tus dependencias a la versión más reciente que se ajuste a las restricciones que definas.
Para recibir notificaciones sobre el lanzamiento de nuevas versiones puede suscribirse a libraries.io, un servicio web que puede supervisar las dependencias y enviarle alertas sobre las actualizaciones.
El Comprobador Local de Seguridad PHP (en Inglés “Local PHP Security Checker”)
es una herramienta de línea de comandos, que examinará su archivo composer.lock
y le dirá si necesita actualizar alguna de sus dependencias.
Composer también puede gestionar dependencias globales y sus binarios. El uso es sencillo, todo lo que necesitas hacer
es anteponer a su comando con global
. Si por ejemplo quieres instalar PHPUnit y tenerlo
disponible globalmente, ejecutarías el siguiente comando:
composer global require phpunit/phpunit
Esto creará una carpeta ~/.composer
donde residen tus dependencias globales. Para que los binarios de los paquetes instalados,
añada la carpeta ~/.composer/vendor/bin
a la variable $PATH
.
Un veterano gestor de paquetes que algunos desarrolladores PHP disfrutan es PEAR. Se comporta de manera similar a Composer, pero tiene algunas diferencias notables.
PEAR requiere que cada paquete tenga una estructura específica, lo que significa que el autor del paquete debe prepararlo para uso con PEAR. No es posible utilizar un proyecto que no haya sido preparado para funcionar con PEAR.
PEAR instala los paquetes globalmente, lo que significa que después de instalarlos una vez están disponibles para todos los proyectos en ese servidor. Esto puede ser bueno si muchos proyectos dependen del mismo paquete con la misma versión, pero puede llevar a problemas si surgen conflictos de versión entre dos proyectos.
Puede instalar PEAR descargando el instalador .phar
y ejecutándolo. La documentación de PEAR tiene
detalladas instrucciones de instalación para cada sistema operativo.
Si usas Linux, también puedes echar un vistazo al gestor de paquetes de tu distribución.
Debian y Ubuntu, por ejemplo, tienen un paquete apt php-pear
.
Si el paquete aparece en la lista de paquetes de PEAR, puede instalarlo especificando el nombre oficial:
pear install foo
Si el paquete se aloja en otro canal, deberá “descubrir” primero el canal y especificarlo también al instalar. Consulta la documentación sobre el uso de canales para obtener más información sobre este tema.
Si ya está utilizando Composer y desea instalar algún código PEAR también, puede utilizar Composer para manejar sus dependencias PEAR. Los repositorios PEAR ya no son soportados directamente por Composer versión 2, por lo que debes añadir manualmente un repositorio para instalar paquetes PEAR:
{
"repositories": [
{
"type": "package",
"package": {
"name": "pear2/pear2-http-request",
"version": "2.5.1",
"dist": {
"url": "https://github.com/pear2/HTTP_Request/archive/refs/heads/master.zip",
"type": "zip"
}
}
}
],
"require": {
"pear2/pear2-http-request": "*"
},
"autoload": {
"psr-4": {"PEAR2\\HTTP\\": "vendor/pear2/pear2-http-request/src/HTTP/"}
}
}
La primera sección "repositorios"
se utilizará para que Composer sepa que debe “inicializar” (o “descubrir” en terminología PEAR)
el repositorio pear. Entonces la sección require
prefijará el nombre del paquete así:
pear-channel/package
El prefijo “pear” está codificado para evitar conflictos, ya que un canal pear puede ser el mismo que el nombre de proveedor de otro paquete, por ejemplo, entonces el nombre corto del canal (o URL completa) puede ser usado para referenciar en qué canal está el paquete.
Cuando se instala este código estará disponible en su directorio de proveedores y automáticamente disponible a través del autocargador de Composer:
vendor/pear2/pear2-http-request/pear2/HTTP/Request.php
Para utilizar este paquete PEAR simplemente haga referencia a él de la siguiente manera:
<?php
require __DIR__ . '/vendor/autoload.php';
use PEAR2\HTTP\Request;
$request = new Request();
PHP es un gran lenguaje que permite la creación de código de forma rápida y eficiente a programadores de todos los niveles. Sin embargo, a medida que se avanza en el lenguaje, es común olvidar (o pasar por alto) los conceptos básicos aprendidos en favor de atajos y/o malas prácticas. Para ayudar a combatir este problema común, esta sección tiene como objetivo recordar a los desarrolladores las buenas prácticas dentro de PHP.
PHP posee una clase llamada DateTime para ayudar en la lectura, escritura, comparación y el cálculo de fechas y tiempo. En PHP aparte de DateTime existen muchas funciones relacionadas con fecha y tiempo, sin embargo, DateTime, provee una interfaz orientada a objeto muy útil la cual se adapta a la mayoría de los casos. Adicional a eso, DateTime permite el manejo de zonas horarias, pero eso está fuera del alcance de esta breve introducción.
Es posible realizar cálculos con DateTime gracias a la clase DateInterval. DateTime posee métodos como add()
and sub()
que
utilizan DateInterval como argumento. No se debe escribir codigo que espere la misma cantidad de segundo en cada día. Tanto el
horario de verano (daylight savings time) como las distintas zonas horarias invalidan esa suposición. En vez de eso, utilice
los intervalos de fechas para hacer sus cálculos. Para calcular la diferencia entre fechas utilice el método diff()
.
Este devolverá un new DateInterval
, el cual puede ser fácilmente impreso en la pantalla.
<?php
$string = '22. 11. 1968';
$inicio = DateTime::createFromFormat('d. m. Y', $raw);
echo 'Fecha inicial: ' . $start->format('Y-m-d') . PHP_EOL;
Es posible realizar calculos con DateTime gracias a la clase DateInterval. DateTime posee metodos como add()
and sub()
que
utilizan DateInterval como argumento. No se debe escribir codigo que espere la misma cantidad de segundo en cada dia. Tanto el
horario de verano (daylight savings time) como las distintas zonas horarias invalidaran esa suposicion. En vez de eso, utilice
los intervalos de fechas para hacer sus calculos. Para calcular la diferencia entre fechas utilice el método diff()
.
Este devolverá un new DateInterval
, el cual puede ser fácilmente impreso en la pantalla.
<?php
// Se crea una copia de $inicio y se le añade un mes y 6 días.
$fin = clone $start;
$fin->add(new DateInterval('P1M6D'));
$diff = $fin->diff($inicio);
echo "Diferencia: " . $diff->format('%m mes, %d días (total: %a días)') . PHP_EOL;
// Diferencia: 1 mes, 6 días (total: 37 días)
Es posible comparar fácilmente los objetos DateTime:
<?php
if($inicio < $fin) {
echo "¡El inicio sucede antes que el final!\n";
}
Este último ejemplo demuestra cómo se utiliza la clase DatePeriod para iterar sobre eventos periódicos. Este puede tomar dos objetos DateTime, uno para el inicio y el otro para el final, y el intervalo que define el número de eventos periódicos que se devuelven.
<?php
// Imprimir todos los jueves entre $inicio y $fin
$intervaloDePeriodo = \DateInterval::createFromDateString('first thursday');
$iteradorDePeriodo = new \DatePeriod($inicio, $intervaloDePeriodo, $fin, \DatePeriod::EXCLUDE_START_DATE);
foreach($iteradorDePeriodo as $fecha)
{
// Imprimir cada fecha en el periodo
echo $fecha->format('m/d/Y') . " ";
}
Una extensión popular del API de PHP es Carbon. Esta hereda todo lo de la clase DateTime, por lo que requiere cambios mínimos del código, pero incluye características adicionales, como el soporte de localización, muchas más forma de sumar, restar y formatear los objetos DateTime, además de medios para probar código gracias a que permite simular cualquier fecha y hora que se desee.
Cuando se está desarrollando una aplicación resulta de mucha utilidad el utilizar patrones de uso común en el código y patrones comunes para la estructura general del proyecto. El uso de patrones comunes es útil porque facilita mucho la gestión del código y permite que otros desarrolladores comprendan rápidamente cómo encaja todo.
Si se utilizan un marco de trabajo (framework) entonces la mayor parte del código de nivel superior y la estructura del proyecto se basarán en ese marco de trabajo, por lo que muchas de las decisiones sobre patrones ya se han tomado por usted. Pero aún depende de usted elegir los mejores patrones para seguir en el código que desarrolla sobre el marco de trabajo. Si, por otro lado, no está utilizando un marco de trabajo para crear su aplicación, entonces debe encontrar los patrones que mejor se adapten al tipo y tamaño de la aplicación que está creando.
Puede obtener más información sobre los patrones de diseño PHP y ver ejemplos prácticos en:
Esta sección fue escrita originalmente por Alex Cabal sobre PHP Best Practices y se ha utilizado como base para nuestras propias recomendaciones acerca de UTF-8.
Ahora mismo, PHP no soporta Unicode a bajo nivel. Hay formas de asegurarse de que las cadenas de texto UTF-8 sean procesadas correctamente, pero no es sencillo, además requiere que profundizar en todos los niveles de la aplicación web, desde HTML, pasando por SQL hasta PHP. Nos esforzamos por hacer un breve resumen práctico.
Las operaciones básicas con cadenas, como la concatenación de dos cadenas o la asignación de cadenas a variables,
no necesitan nada especial de UTF-8. Sin embargo, la mayoría de las funciones para el manejo de cadenas como
strpos()
o strlen()
, necesitan consideración especial. A menudo, estas funciones tienen su contraparte con
funciones mb_*
como por ejemplo: mb_strpos()
o mb_strlen()
. Estas funciones mb_*
están disponibles para usted
vía la extensión para el manejo de Cadenas de Caracteres Cadenas Multibyte,
y están diseñadas específicamente para operar con cadenas Unicode.
Siempre se debe utilizar las funciones mb_*
para trabajar con cadenas Unicode. Por ejemplo, si usa substr()
sobre
una cadena UTF-8, hay una gran posibilidad de que el resultado incluya algunos caracteres ilegibles. La función adecuada
a usar es su contraparte multibyte, mb_substr()
.
La parte difícil es recordar utilizar las funciones mb_*
todo el tiempo. Si se olvida incluso una sola vez, su
cadena Unicode podría quedar ilegible durante procesamientos posteriores.
No todas las funciones de cadena tienen una contraparte mb_*
. Si no existe alguna para lo que se quiere hacer, entonces
te quedaste sin suerte.
Se Debe utilizar la función mb_internal_encoding()
al inicio de cualquier script PHP que escriba (o al inicio de su
script de inclusión global), y la función mb_http_output()
justo después, si su script genera salidas hacia un navegador.
Definiendo explícitamente la codificación de sus cadenas en cada script le ahorrará muchos dolores de cabeza en el futuro.
Adicionalmente, muchas funciones de PHP que operan sobre cadenas tienen un parámetro opcional que le permite especificar
la codificación de caracteres. Siempre se debe indicar explícitamente UTF-8 cuando se les da la opción. Por ejemplo,
htmlentities()
tiene una opción para la codificación de caracteres, y siempre se debe especificar UTF-8 si se trata con este
tipo de cadenas. Tenga en cuenta que a partir de PHP 5.4.0, UTF-8 es la codificación por defecto para htmlentities()
y
htmlspecialchars()
.
Por último, si usted está construyendo una aplicación distribuida y no puede estar seguro de que la extensión mbstring
estará
habilitada, considere el uso del paquete de Composer symfony/polyfill-mbstring.
Este usará mbstring
si está disponible y recurrirá a funciones que no sean UTF-8 si no lo está.
Si su script accede a MySQL, existe la posibilidad de que sus cadenas se almacenen como cadenas no UTF-8 en la base de datos incluso si sigue todas las precauciones anteriores.
Para asegurarse de que sus cadenas van de PHP a MySQL como UTF-8, establezca el juego de caracteres y el cotejamiento (collation) a utf8mb4
para su base de datos y todas sus tablas, utilice también utf8mb4
en la cadena de conexión PDO. Vea el código de ejemplo a continuación.
Esto es de importancia crítica.
Tenga en cuenta de que debe usar el juego de caracteres utf8mb4
y no utf8
para un soporte completo UTF-8. Lea más adelante para saber por qué.
Utilice la función mb_http_output()
para garantizar que su script PHP genera una salida con cadenas UTF-8 hacia su navegador.
Luego, la respuesta HTTP deberá indicarle al navegador que esta página debe considerarse como UTF-8. Hoy en día, es común configurar el conjunto de caracteres en el encabezado de respuesta HTTP de esta manera:
<?php
header('Content-Type: text/html; charset=UTF-8')
El enfoque histórico para hacerlo era incluir la charset <meta>
tag etiqueta <head>
en la página.
<?php
// Indicarle a PHP que usaremos cadenas UTF-8 hasta el final del script.
mb_internal_encoding('UTF-8');
$utf_set = ini_set('default_charset', 'utf-8');
if (!$utf_set) {
throw new Exception('No se pudo establecer default_charset a utf-8, ¡asegúrese de que esté configurado en su sistema!');
}
// Indicarle a PHP que se imprimirá UTF-8 al navegador
mb_http_output('UTF-8');
// Nuestra cadena de prueba UTF-8
$cadena = 'Êl síla erin lû e-govaned vîn.';
// Transforma la cadena de alguna manera con una función multibyte
// Observe cómo cortamos la cadena en un carácter que no es ASCII para fines de demostración
$cadena = mb_substr($string, 0, 15);
// Conéctese a una base de datos para almacenar la cadena transformada
// Vea el ejemplo de PDO en este documento para obtener más información
// Tenga en cuenta el `charset=utf8mb4` en el Nombre del origen de datos (DSN)
$enlace = new PDO(
'mysql:host=your-hostname;dbname=your-db;charset=utf8mb4',
'tu-nombredeusuario',
'tu-clave',
array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_PERSISTENT => false
)
);
// Almacenamos nuestra cadena transformada como UTF-8 en nuestra base de datos
// Su base de datos y sus tablas están en el conjunto de caracteres y la intercalación utf8mb4, ¿verdad?
$handle = $enlace->prepare('insert into ElvishSentences (Id, Body, Priority) values (default, :cadena, :prioridad)');
$handle->bindParam(':cadena', $cadena, PDO::PARAM_STR);
$prioridad = 45;
$handle->bindParam(':prioridad', $prioridad, PDO::PARAM_INT); // Se le indica de forma explicita a pdo que se le dara un entero.
$handle->execute();
// Recuperamos la cadena guardada para verificar que está correctamente almacenada.
$handle = $enlace->prepare('select * from ElvishSentences where Id = :id');
$id = 7;
$handle->bindParam(':id', $id, PDO::PARAM_INT);
$handle->execute();
// Almacenamos el resultado en un objeto que nos permitirá generar HTML después
// Este objeto no tendrá efecto mayor en memoria ya que se recupera los datos por medio del método Justo a Tiempo (JIT)
$resultado = $handle->fetchAll(\PDO::FETCH_OBJ);
// Un contenedor de ejemplo que le permite escapar datos a HTML.
function escape_a_html($dirty){
echo htmlspecialchars($dirty, ENT_QUOTES, 'UTF-8');
}
header('Content-Type: text/html; charset=UTF-8'); // Innecesario si el default_charset ya esta seteado como utf-8.
?><!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Página de prueba para UTF-8</title>
</head>
<body>
<?php
foreach($resultado as $row){
escape_a_html($row->Body); // Esto debería mostrar correctamente nuestra cadena UTF-8 transformada en el navegador.
}
?>
</body>
</html>
Aviso legal para los recién llegados: i18n y l10n son numerónimos, un tipo de abreviatura en la que se utilizan números para acortar palabras. En nuestro caso, la internacionalización se convierte en i18n y la localización, en l10n.
En primer lugar, necesitamos definir esos dos conceptos similares y otras cosas relacionadas:
La internacionalización es cuando organizas tu código de tal forma que pueda adaptarse a diferentes idiomas o regiones sin refactorizaciones. Esta acción se realiza normalmente una vez, preferiblemente al principio del proyecto, o de lo contrario probablemente necesitarás realizar cambios enormes en el código fuente.
La localización ocurre cuando adaptas la interfaz (principalmente) traduciendo contenidos, en función del trabajo de i18n realizado anteriormente. Por lo general, se realiza cada vez que un nuevo idioma o región necesita soporte y se actualiza cuando se agregan nuevas partes de la interfaz, ya que deben estar disponibles en todos los idiomas compatibles.
La pluralización define las reglas necesarias entre distintos idiomas para interoperar cadenas que contienen números y contadores. Por ejemplo, en inglés, cuando solo tienes un elemento, es singular y todo lo que sea diferente se llama plural; el plural en este idioma se indica agregando una S después de algunas palabras y, a veces, cambia partes de la palabra. En otros idiomas, como el ruso o el serbio, hay dos formas plurales además del singular; incluso es posible encontrar idiomas con un total de cuatro, cinco o seis formas, como el esloveno, el irlandés o el árabe.
La forma más fácil de internacionalizar aplicaciones PHP es mediante el uso de archivos de array y utilizar dichas cadenas
de texto en plantillas, como por ejemplo <h1><?=$TRANS['title_about_page']?></h1>
. Sin embargo, esta forma no se
recomienda para proyectos serios, ya que plantea algunos problemas de mantenimiento en el camino; algunos pueden aparecer
al principio, como la pluralización. Por lo tanto, no intente esto si su proyecto contiene más de un par de páginas.
La forma más clásica y que a menudo se toma como referencia para i18n y l10n es una herramienta Unix llamada gettext
. Data de 1995 y sigue siendo una implementación completa para traducir software. Es bastante fácil de poner en funcionamiento,
mientras que todavía cuenta con potentes herramientas de soporte. Hablaremos aquí sobre Gettext. Además, para ayudarte a no
complicarte en la línea de comandos, presentaremos una excelente aplicación GUI(interfaz gráfica de usuario) que se puede
usar para actualizar fácilmente tu fuente l10n.
Hay librerías de uso común que soportan Gettext y otras implementaciones de i18n. Algunas de ellas pueden parecer más fáciles de instalar, tener características adicionales, o formatos de archivo i18n. En este documento, nos centramos en las herramientas proporcionadas con el núcleo de PHP, pero enumeramos otras para complementar:
intl
(incluidos los mensajes en plural).gettext
) y también puede exportar a otros formatos además de los archivos .mo/.po
. Puede ser útil si necesita integrar
sus archivos de traducción en otras partes del sistema, como una interfaz de JavaScript.strtr()
internamente.Otros marcos de trabajo(frameworks) también incluyen modulos i18n, pero estos no estan disponibles fuera de su codigo.
@lang
para archivos de plantilla.Intl
, disponible desde la versión php 5.3, y basada en el ICU project; esto permite a Yii correr poderosos
reemplazos, como la representación en palabras de números, fechas formateadas, hora, intervalo, monedas, y ordinales.Si decides escoger una de las librerías que no proveen extractor, podrías querer utilizar el formato gettext, así puedes utilizar las utilidades de gettext (incluyendo Poedit) como han sido descritas en el resto del capítulo.
Podrias necesitar instalar Gettext y el resto de librerías php relacionadas por medio de tu manejador de paquetes,
como apt-get
o yum
. luego de instalado, debes activarlo agregando ya sea extension=gettext.so
si estas en Linux/Unix o
extension=php_gettext.dll
si estas en Windows, a tu archivo php.ini
.
También se estará utilizando Poedit para crear archivos de traducción. Es probable que lo encuentres en el manejador de paquetes de tu sistema; Está disponible para Unix, macOS, y Windows, además puede ser descargado gratis en su web.
Existen 3 tipos de archivos que se suelen utilizar cuando se trabaja con gettex. los principales son los archivos PO (objeto portable) y MO (objeto máquina), el primero siendo una lista de “objetos traducidos” leible y el segundo, los binarios correspondientes que serán interpretados por gettext mientras se realiza la localización. Además también existe un archivo POT (plantilla), el que simplemente contiene todas las llaves existentes de tu código fuente, y puede ser utilizado como una guía para generar y actualizar todos los archivos PO. Estos archivos plantilla no son obligatorios: depende de la herramienta que estés utilizando para realizar l10n, podría ser suficiente con solo los archivos PO/MO. Siempre tendrás una pareja de archivos PO/MO por cada lenguaje y región, pero solo un archivo un archivo POT por dominio.
Existen algunos casos, en grandes proyectos, donde podría ser necesario separar la traducción cuando una misma palabra puede tener un significado diferente dependiendo del contexto. En esos casos, puedes separarla en diferentes dominios. Ellos son, básicamente, grupos nombrados de archivos POT/PO/MO, donde los nombres de los archivos son el dominio de traducción. Proyecto pequeños y medianos suelen, por simplicidad, utilizan un solo dominio; el nombre es arbitrario, pero utilizaremos “principal” en los códigos de ejemplo. In los proyectos Symfony, por ejemplo, los dominios son utilizados para separar la traducción para los mensajes de validación.
Un local es un código sencillo que identifica una versión de un lenguaje. Está definido siguiendo las especificaciones de los estándar ISO 639-1 y ISO 3166-1 alpha-2: dos letras en minúsculas para el lenguaje, opcionalmente puede estar seguido por un guión bajo y dos letras mayúsculas identificando el país o el código regional. para lenguajes extraños, tres letras son utilizados.
Para algunos parlantes, el país puede parecer redundante. De hecho, algunos lenguajes tienen diferentes dialectos
en diferentes países, tal es el caso de Aleman Australiano (de_AT
) o el Portugués de Brasil (pt_BR
). la segunda
parte es utilizado para distinguir entre estos dos dialectos - cuando no está presente, se coma como una versión “genérica”
o “híbrida” del lenguaje.
Para utilizar Gettext, primero necesitamos seguir una estructura específica de archivos. Primero, se tiene que seleccionar
una carpeta raíz arbitraria para los archivos l10n en tu código fuente. Dentro de esta, se tendrá una carpeta por cada local,
y una carpeta LC_MESSAGES
que contendrá todos los pares PO/MO. Ejemplo:
<project root>
├─ src/
├─ templates/
└─ locales/
├─ forum.pot
├─ site.pot
├─ de/
│ └─ LC_MESSAGES/
│ ├─ forum.mo
│ ├─ forum.po
│ ├─ site.mo
│ └─ site.po
├─ es_ES/
│ └─ LC_MESSAGES/
│ └─ ...
├─ fr/
│ └─ ...
├─ pt_BR/
│ └─ ...
└─ pt_PT/
└─ ...
Como se dijo en la introducción, diferentes lenguajes pueden tener diferentes formas plurales. Sin embargo, gettext te
ahorra estos problemas. Cuando se crea un nuevo archivo .po
, tendrás que declarar las reglas plurales para
ese lenguaje, y las piezas traducidas que son sensitivas al plural tendrán una forma para cada una de estas reglas. Cuando
se llame a Gettext en el código, necesitará especificar la cantidad relacionada a la oración, y el se encargara de
usar la forma correcta - incluso utilizar sustitución de cadena de ser necesario.
Las reglas de plural incluyen la cantidad de plurales disponibles y una prueba booleana con n
que definiría en qué
regla se encuentra el número dado (comenzando el conteo con 0). Por ejemplo:
nplurals=1; plural=0
- Solo una reglas.nplurals=2; plural=(n != 1);
- 2 reglas, la primera si n es igual a 1, la segunda si es diferente a 1.nplurals=2; plural=(n > 1);
- 2 Reglas, segunda si n es mayor a uno, la primera si no lo es.Ahora que comprendes las bases de cómo funcionan las reglas para el plural - y en caso de que no, por favor lee una explicacion mas a fondo LingoHub tutorial -, podrias querer copias las que necesitas es una lista en lugar de escribirlas a mano.
Cuando invocas a Gettext para realizar una localización en oraciones con contadores, necesitarás proveer también
el número relacionado. Gettext determinará las reglas que se deben aplicar y usará la versión de localización correcta.
Necesitarás incluir en el archivo .po
una sentencia diferente por cada regla plural definida.
Luego de tanto teoría, es momento de ir a la práctica. Aquí un fragmento de un archivo .po
- no le prestes atención
a su formato, si no a su contenido general; Luego aprenderás como editarlo fácilmente.
msgid ""
msgstr ""
"Language: pt_BR\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
msgid "Estamos traduciendo algunas cadenas"
msgstr "Nós estamos traduzindo algumas strings agora"
msgid "Hola %1$s! tu última visita fue el %2$s"
msgstr "Olá %1$s! Sua última visita foi em %2$s"
msgid "Solo un mensaje sin leer"
msgid_plural "%d mensajes sin leer"
msgstr[0] "Só uma mensagem não lida"
msgstr[1] "%d mensagens não lidas"
La primera sección funciona como una cabecera, teniendo los msgid
and msgstr
vacios(mensaje id, mensaje string). Esta describe
la codificación del archivo, la forma plural y otras cosas son menos relevantes.
La segunda sección traduce una cadena sencilla desde el español al Portuges de Brasil, y la tercera hace lo mismo, pero
utilizando el reemplazo de cadena de sprintf
así la traducción puede contener el nombre y la fecha de visita.
La últimas sección es un muestra de la forma de pluralización, mostrando tanto la forma singular y plural como msgid
en
español, y su traducción correspondiente como msgstr
0 y 1 (siguiendo los números dado en las reglas de forma plural). aquí,
el reemplazo de cadena es utilizado también para que el número puede ser visto directamente en la sentencia. con el uso de %d
.
La forma plural siempre tiene dos msgid
(singular y plural), por lo que es aconsejado no utilizar un lenguaje complicado
como base del recurso de traducción.
Como podrás haber notado, estamos utilizando como recurso de id la sentencia en español. ese msgid
será el mismo
utilizado en todos tus archivos .po
, por lo que los otros lenguajes tendrán el mismo formato y el mismo campo msgid
pero líneas msgstr
traducidas.
Hablando de llaves de traduccion, existen 2 vertientes principales:
msgid
como una sentencia real.
La ventaja principal sería:
- Si hay partes del programa sin traducir en algún lenguaje en específico, la llave mostrada mantendrá algún un poco
poco del significado. Por ejemplo: si eres capaz de traducir de Español a Ingles sin ningun problema, pero necesitas algo
de ayuda para traducir al francés, podrias publicar primero la página faltando algunas traducciones de sentencias en
Francés, y parte de la interfaz en local Francés será mostrado en español en su lugar;
- Es mucho más fácil para el traductor entender el contexto y realizar una traducción apropiada basado en el msgid
.
- Te da un l10 “gratis” para un lenguaje - el principal;
- La única desventaja: si necesitas cambiar el texto actual, tendrías que reemplace el mismo msgid
en todos los
archivos de lenguaje.
msgid
as a unique, structured key.
Esta describiría el rol de la sentencia en la aplicación de una forma estructurada, incluyendo la plantilla o parte
donde la cadena está ubicada actualmente en lugar de su contenido.
- Es una gran manera de tener el código organizado, separando el contenido del texto de la lógica de la plantilla.
- Sin embargo, esto podría traerle problemas al traductor que perdería el contexto. Un archivo de lenguaje principal
sería necesario como una base para las otras traducciones. Ejemplo: el desarrollador tendrá idealmente un archivo
es.po
, que el traductor tendría que leer para entender que debería escribir, por ejemplo, en fr.po
.
- Traducciones faltantes mostrarían llaves sin un claro significado (menu_principal.bienvenido
en lugar de
Hola, sea bienvenido
). Lo positivo es que forzará la traducción a estar completa antes de publicar la app - sin
embargo, tan mal como podrían ser problemas de traducción en la interfaz. Algunas librerías incluyen una opción para
especificar un lenguaje de respaldo, obteniendo así un comportamiento parecido a la estrategia anterior.
El manual Gettext favorece la primera estrategia debido a que, en general, es más fácil para los traductores y usuarios en caso de problema. Por lo que esa es la forma en la que trabajaremos aquí. Sin embargo, la Documentación de Symfony favorece la traducción basada en palabras claves, para permitir cambios independientes de todas las traducciones sin afectar a las plantillas.
En una aplicación típica, utilizar algunas funciones Gettext mientras escribes texto estático en tus páginas. Estas
sentencias aparecen en los archivos .po
, se traducirían, compilaron en archivos .mo
y entonces, serían utilizados
por Gettext cuando se renderiza la interfaz actual. Con lo anterior, armemos todo lo que se ha discutido hasta el momento en
un ejemplo paso a paso:
<?php include 'i18n_setup.php' ?>
<div id="cabecera">
<h1><?=sprintf(gettext('Bienvenido, %s!'), $nombre)?></h1>
<!-- código indentado de esta forma solo para mejorar la lectura -->
<?php if ($sinLeer): ?>
<h2><?=sprintf(
ngettext('Un mensaje sin leer',
'%d mensajes sin leer',
$sinLeer),
$sinLeer)?>
</h2>
<?php endif ?>
</div>
<h1><?=gettext(''Introducción'')?></h1>
<p><?=gettext('Ahora estamos traduciendos algunos textos')?></p>
gettext()
Simplemente traduce un msgid
a su msgstr
correspondiente para un lenguaje especificado. También
existe una funcion corta _()
que trabaja de la misma manera.ngettext()
hace lo mismo pero con reglas de plural;dgettext()
y dngettext()
, que permite sobreescribir el dominio de la próxima
llamada. Más sobre configuración de dominios en el próximo ejemplo.that allow you to override the domain for a singlei18n_setup.php
como se utilizó en el ejemplo anterior), seleccionando el local correcto yConfigurando Gettext.
<?php
/**
* Verifica si el $local especificado es soportado en el proyecto
* @param string $local
* @return bool
*/
function valido($local) {
return in_array($local, ['en_US', 'en', 'pt_BR', 'pt', 'es_ES', 'es']);
}
//especificando el local por defecto, para propósitos informativos.
$lang = 'en_US';
if (isset($_GET['lang']) && valid($_GET['lang'])) {
// El local puede ser cambiado por medio del query-string
$lang = $_GET['lang']; //deberías sanitizar esto!..
setcookie('lang', $lang); //Se almacena en una cookie para que así pueda ser reutilizado.
} elseif (isset($_COOKIE['lang']) && valid($_COOKIE['lang'])) {
// Si esta presenta la cookie, se utiliza su valor.
$lang = $_COOKIE['lang']; //deberías sanitizar esto!.
} elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
// defecto: Determinar cuál es el lenguaje que el navegador dice que el usuario acepta.
$langs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
array_walk($langs, function (&$lang) { $lang = strtr(strtok($lang, ';'), ['-' => '_']); });
foreach ($langs as $browser_lang) {
if (valid($browser_lang)) {
$lang = $browser_lang;
break;
}
}
}
// Aquí definiremos el sistema local global en base al lenguaje obtenido.
putenv("LANG=$lang");
// Esto podría ser útil para funciones de fecha (LC_TIME) o formateo de dinero (LC_MONETARY).
setlocale(LC_ALL, $lang);
// Esto hará que Gettext busque en ../locales/<lang>/LC_MESSAGES/main.mo
bindtextdomain('main', '../locales');
// Indica el codificado que se debe utilizar para leer el archivo.
bind_textdomain_codeset('main', 'UTF-8');
// Si tu aplicación tiene dominios adicionales, como mencioné anteriormente, deberías enlazarlos todos aquí también.
bindtextdomain('forum', '../locales');
bind_textdomain_codeset('forum', 'UTF-8');
// Aquí indicamos el dominio por defecto que las llamadas gettext() deberían utilizar.
textdomain('main');
// Esto buscará la cadena en forum.mo en lugar de main.mo.
// echo dgettext('forum', 'Welcome back!');
?>
Una de las grandes ventajas de Gettext tiene sobre paquetes custom i18n de marcos de trabajoes su extensivo y poderoso formato de archivo. “Rayos, esto es muy complicado para entender y editar a mano, una matriz sería mucho más sencillo!” No te confundas, aplicaciones como Poedit están aquí para ayudarte - mucho. Puedes obtener el program desde su sitio oficial, es gratis y está disponible en todas las plataformas. Es una herramienta muy sencilla de utilizar, y además una muy poderosa - utilizando todas las características que Gettext tiene disponible. Esta guía está basada en PoEdit 1.8.
En la primera ejecución, debes seleccionar “File > New…” desde el menú. Se te preguntará directamente por el idioma:
aquí puedes seleccionar/filtrar los lenguajes a los que quieres traducir, o utiliza el formato que mencionamos anteriormente,
como son en_US
o pt_BR
.
Luego, guarda el archivo - utilizando la estructura de directorios ya mencionados. Después deberías darle click a “Extract from sources”, y aquí configuraras varias opciones para las tareas de extracción y traducción. Serás capaz de encontrar esto luego en el menú “Catalog > Properties”:
-Source paths: Aquí debes incluir todos las carpetas del proyecto donde gettext()
(y hermanos) son llamados -
esta será usualmente tu carpeta de plantillas/vistas. Este es la única configuración obligatoria.
gettext()
y llamadas a funciones similares en diferentes
lenguajes de programación, además podrías crear tus propias funciones de traducción. Aquí sería donde agregarías
todos esos métodos. De esto se discutirá luego en la sección de “tips”.Luego de especificar todos esos puntos ejecuta un escaneo a tu archivos fuente y encontrará todas las llamadas a
localización. Luego de cada escaneo PoEdit mostrará un resumen de lo que fue encontrado y lo que fue removido en
dichos archivos. Las nuevas entradas se cargaran vacías en las tablas de traducción, y comenzaras a escribir en las
versiones localizadas de esas cadenas de texto. Guarda y un archivo .mo
será (re)compilado en la misma carpeta
y listo!: tu proyecto está internacionalizado.
Cómo podrías haber notado, existen dos tipos principales de cadenas para localización, las sencillas y aquellas con formas plural. La primera solo tiene dos cajas sencillas: source(fuente) y localized string (cadena localizada). La cadena fuente no puede ser modifica debido a que Gettext/Poedit no incluye la capacidad de alterar tus archivos fuente - Tu deberás cambiar el origen directamente y volver a escanear los archivos. Consejo: puedes darle click derecho a una línea de traducción y este te dará una pista del archivo origen y la línea donde esa cadena de texto está siendo utilizada. Por otro lado, las cadenas de forma plural tienen dos cajas para mostrar las dos cadenas fuente, y pestañas para que puedas configurar las diferentes formas finales.
Cada vez que cambies tus fuentes y necesites actualizar las traducciones, solo presiona Refresh y Poedit volverá a escanear el Código, removiendo entradas inexistentes, fusionando las que han cambiado con las que se han agregado. Incluso podría intentar adivinar algunas de las traducciones, basado en otras que has realizado. Esas conjeturas y las entradas cambiadas recibirán una marca “Fuzzy”, indicando que requiere verificación, mostrándose dorados en el listado. También es útil si tienes un equipo de traducción y alguien intenta escribir algo sobre lo que no esta seguro: solo necesita marcar “Fuzy”, y alguien más lo verifica luego.
Finalmente, es aconsejado dejar “View > Untranslated entries first” marcado, ya que esto ayudará mucho a no olvidar ninguna entrada. Desde ese menú, también puedes abrir otras partes de la UI que te permiten dejar información contextual para los traductores de ser necesarios.
Si está ejecutando PHP como un módulo en Apache (mod_php
), puedes tener problemas con el almacenamiento en
caché del archivo .mo
. Esto sucede la primera vez que se lee y, luego, para actualizarlo, es posible que deba reiniciar
el servidor. En Nginx y PHP5, generalmente solo se necesitan un par de actualizaciones de página para actualizar el
caché de traducción y, en PHP7, rara vez es necesario.
Como prefieren muchas personas, es más fácil usar _()
en lugar de gettext()
. Muchas bibliotecas i18n personalizadas
de frameworks también usan algo similar a t()
para hacer que el código traducido sea más corto. Sin embargo, esa
es la única función que tiene un atajo. Es posible que desee agregar en su proyecto algunas otras, como __()
o _n()
para ngettext()
, o tal vez un _r()
sofisticado que uniría las llamadas gettext()
y sprintf()
. Otras bibliotecas, como
Gettext de php-gettext también proporcionan funciones auxiliares como estas.
En esos casos, necesitarás indicarle a la utilidad Gettext cómo extraer las cadenas de esas nuevas funciones. No
temas; es muy fácil. Es solo un campo en el archivo .po
, o una pantalla de Configuración en Poedit. En el editor,
esa opción está dentro de “Catalog > Properties > Source keywords”. Recuerda: Gettext ya conoce las
funciones predeterminadas para muchos idiomas, así que no temas si esa lista parece vacía. Debes incluir allí las
especificaciones de esas nuevas funciones, siguiendo un formato específico:
t()
que simplemente devuelve la traducción de una cadena, puedes especificarlo como
t
. Gettext sabrá que el único argumento de la función es la cadena que se va a traducir;__('one user', '%d users', $number)
,
la especificación sería __:1,2
, lo que significa que la primera forma es el primer argumento y la segunda
forma es el segundo argumento. Si tu número viene como el primer argumento, la especificación sería
__:2,3
, lo que indica que la primera forma es el segundo argumento, y así sucesivamente.Después de incluir esas nuevas reglas en el archivo .po
, un nuevo escaneo traerá sus nuevas cadenas con la misma
facilidad que antes.
De Wikipedia:
Inyección de dependencias (Dependency Injection, DI) es un patrón de diseño en el que se suministran objetos a una clase en lugar de ser la propia clase la que cree dichos objetos. Esos objetos cumplen contratos que necesitan nuestras clases para poder funcionar (de ahí el concepto de dependencia).
Esta cita hace que el concepto suene mucho más complejo de lo que es en realidad. La inyección de dependencias consiste en proporcionar a un componente sus dependencias a través de la inyección en constructor, llamadas a métodos o la configuración de propiedades. Es así de simple.
Podemos demostrar el concepto con un simple pero a la vez inofencivo ejemplo.
Tenemos una clase Database
que requiere un adaptador para comunicarse con la base de datos.
Instanciamos el adaptador en el constructor y creamos una dependencia rígida.
Esto dificulta las pruebas y significa que la clase Database
esta fuertemente acoplada al adaptador.
<?php
namespace Database;
class Database
{
protected $adapter;
public function __construct()
{
$this->adapter = new MySqlAdapter;
}
}
class MysqlAdapter {}
Este código se puede refactorizar para usar Inyección de Dependencia y de esta manera desacoplamos la dependencia. Aquí, inyectamos la dependencia en un constructor haciendo uso de la promoción de propiedades en el constructor y de esta manera estará disponible como una propiedad de la clase:
<?php
namespace Database;
class Database
{
public function __construct(protected MySqlAdapter $adapter)
{
}
}
class MysqlAdapter {}
Ahora le estamos dando a la clase Database
su dependencia en lugar de crearla directamente.
Incluso podríamos crear un método que acepte un argumento de la dependencia y configurarla
de esa manera, o si la propiedad $adapter
fuera public
podríamos configurarla directamente.
Si alguna vez has leído sobre Inyección de Dependencias es probable que hayas visto los términos “Inversión de control” o “Principio de Inversión de Dependencias”. Estos son los problemas complejos que resuelve la Inyección de Dependencias.
Inversión de Control, como su nombre lo indica, es “invertir el control” de un sistema al mantener el control organizacional completamente separado de nuestros objetos. En términos de Inyección de Dependencias, esto significa desacoplar nuestras dependencias al controlarlas e instanciarlas en otras partes del sistema.
Durante años, los frameworks PHP han estado logrando la Inversión de Control, sin embargo, surge la pregunta, ¿qué parte del control estamos invirtiendo y hacia dónde? Por ejemplo, los frameworks MVC generalmente proveen un superobjeto o controlador base que otros controladores deben extender para obtener acceso a sus dependencias. Esto es Inversión de Control, sin embargo, en lugar de desacoplar las dependencias, este método simplemente las mueve.
La Inyección de Dependencia nos permite resolver este problema de una forma mas elegante al inyectar solamente las dependencias que necesitamos, cuando la necesitamos sin la necesidad de tener dependencias en duro.
El Principio de Responsabilidad Única (en inglés Single Responsibility Principle) se refiere a los actores y a la arquitectura de alto nivel. Establece que “Una clase debería tener solo una razón para cambiar”. Esto significa que cada clase debería solo tener responsabilidad sobre una única parte de la funcionalidad proporcionada por el software. El mayor beneficio de este enfoque es que permite una mejor reutilización del código. Al diseñar nuestras clases para que hagan solo una cosa, podemos utilizar (o reutilizarlas) en cualquier otro programa sin cambiarlas.
El Principio abierto/cerrado (Open/Closed Principle) se refiere al diseño de clases y la extensión de funcionalidades. Establece que “Las entidades de software (clases, módulos, funciones, etc.) deben estar abiertas a la extensión, pero cerradas a la modificación”. Esto significa que debemos diseñar nuestros módulos, clases y funciones de manera que cuando se necesite una nueva funcionalidad, no deberíamos modificar nuestro código existente sino que escribamos código nuevo que será utilizado por el código existente. En términos prácticos, esto significa que deberíamos escribir clases que implementen y respeten las interfaces, luego hacer sugerencias de tipos hacía esas interfaces en lugar de clases específicas.
El mayor beneficio de este enfoque es que podemos extender nuestro código muy fácilmente con soporte para algo nuevo sin tener que modificar el código existente, lo que significa que podemos reducir el tiempo de Control de Calidad (QA) y el riesgo de un impacto negativo a la aplicación se reduce considerablemente. Podemos desplegar nuevo código más rápido y con más confianza.
El Principio de Sustitución de Liskov (Liskov Substitution Principle) se refiere a la subtipificación y la herencia. Establece que “Las clases hijas nunca deben romper las definiciones de tipo de la clase padre”. O, en palabras de Robert C. Martin, “Los subtipos deben ser sustituibles por sus tipos base”.
Por ejemplo, si tenemos una interfaz FileInterface
que define un método embed()
, y contamos con las clases Audio
y Video
las cuales implementan esta interfaz FileInterface
, podemos esperar que el uso del método embed()
siempre haga lo que pretendemos.
Si más adelante creamos una clase PDF
o una clase Gist
que también implementen la interfaz FileInterface
, ya sabremos
y entenderemos lo que hará el método embed()
. El mayor beneficio de este enfoque es que tenemos la capacidad de construir
programas flexibles y fácilmente configurables, ya que cuando cambiamos un objeto de un tipo (por ejemplo, FileInterface
)
por otro, no necesitamos modificar más nada en nuestro programa.
El Principio de Segregación de Interfaces (Interface Segregation Principle, ISP por sus siglas en inglés) trata sobre la comunicación entre la lógica de negocio y los clientes. Establece que “Ningún cliente debería verse obligado a depender de métodos que no utiliza”. Esto quiere decir que en lugar de tener una única interfaz monolítica que todas las clases conformantes deben implementar, deberíamos en su lugar proporcionar un conjunto de interfaces más pequeñas y específicas por concepto que una clase conformante implemente una o más de ellas.
Por ejemplo, una clase Car
o Bus
estaría interesada en un método steeringWheel()
, pero una
clase Motorcycle
o Tricycle
no lo estaría. Por otro lado, una clase Motorcycle
o Tricycle
se interesaría en un método handlebars()
, mientras que una clase Car
o Bus
no. No es necesario
que todos estos tipos de vehículos implementen soporte tanto para steeringWheel()
como para handlebars()
,
por lo que deberíamos descomponer la interfaz original.
El Principio de Inversión de Dependencias (Dependency Inversion Principle) trata sobre eliminar los vínculos rígidos entre clases discretas para que se pueda aprovechar nueva funcionalidad al pasar una clase diferente. Establece que se debe “depender de abstracciones. No depender de implementaciones”. En términos simples, esto significa que nuestras dependencias deberían ser interfaces/contratos o clases abstractas en lugar de implementaciones concretas. Podemos fácilmente refactorizar el ejemplo anterior para seguir este principio.
<?php
namespace Database;
class Database
{
public function __construct(protected AdapterInterface $adapter)
{
}
}
interface AdapterInterface {}
class MysqlAdapter implements AdapterInterface {}
Hay varios beneficios al hacer que la clase Database
ahora dependa de una interfaz en lugar de una implementación concreta.
Consideremos que estamos trabajando en un equipo y el adaptador está siendo desarrollado por un colega. En nuestro primer ejemplo, tendríamos que esperar a que dicho colega termine el adaptador antes de poder simularlo adecuadamente para nuestras pruebas unitarias. Ahora que la dependencia es una interfaz/contrato, podemos simular esa interfaz sin problemas, sabiendo que nuestro colega construirá el adaptador basado en ese contrato.
Un beneficio incluso aún mayor de este enfoque es que nuestro código ahora es mucho más escalable. Si dentro de un año decidimos que queremos migrar a un tipo diferente de base de datos, podemos escribir un adaptador que implemente la interfaz original e inyectar eso en su lugar, no se requeriría más refactorización ya que podemos asegurar que el adaptador sigue el contrato establecido por la interfaz.
Lo primero que deberías entender sobre los Contenedores de Inyección de Dependencias es que no son lo mismo que la Inyección de Dependencias. Un contenedor es una herramienta de conveniencia que nos ayuda a implementar la Inyección de Dependencias; sin embargo, pueden ser y a menudo se usan de forma incorrecta para implementar un anti-patrón, Localización de Servicios. Inyectar un contenedor de DI como Localizador de Servicios en tus clases puede crear una dependencia más fuerte en el contenedor que la dependencia que estás reemplazando. Esto además hace que tu código sea mucho menos transparente y en última instancia más difícil de probar.
La mayoría de los frameworks modernos tienen su propio Contenedor de Inyección de Dependencias que te permite conectar tus dependencias a través de la configuración. Lo que esto significa en la práctica es que puedes escribir código de aplicación que sea tan limpio y desacoplado como el framework en el que se basa.
Muchas veces su código PHP utilizará una base de datos para persistir información. Tiene algunas opciones para conectarse e interactuar con su base de datos. La opción recomendada hasta PHP 5.1.0 era usar controladores nativos como mysqli, pgsql, mssql, etc.
Los drivers nativos son geniales si sólo estás usando una base de datos en tu aplicación, pero si, por ejemplo, estás usando MySQL y un poco de MSSQL, o necesitas conectarte a una base de datos Oracle, entonces no podrás usar los mismos drivers. Tendrás que aprender una API completamente nueva para cada base de datos — y eso puede llegar a ser una tontería.
La extensión mysql para PHP es increíblemente antigua y ha sido reemplazada por otras dos extensiones:
No sólo el desarrollo de mysql se detuvo hace mucho tiempo, sino que además ha sido oficialmente eliminado en PHP 7.0.
Para ahorrarse la búsqueda en su php.ini
para ver qué módulo está utilizando, una opción es buscar mysql_*
en el editor de su elección. Si aparecen funciones como mysql_connect()
y mysql_query()
, entonces está usando mysql
.
Incluso si aún no está utilizando PHP 7.x o posterior, no considerar esta actualización lo antes posible le acarreará mayores dificultades cuando se produzca la actualización de PHP. La mejor opción es reemplazar el uso de mysql por mysqli o PDO en tus aplicaciones dentro de tus propios calendarios de desarrollo para que no te veas apurado más adelante.
Si está actualizando de mysql a mysqli, tenga cuidado con las guías de actualización perezosas que sugieren que simplemente puede encontrar y reemplazar mysql_*
con mysqli_*
. No sólo es una simplificación excesiva, sino que pierde las ventajas que mysqli proporciona, como la vinculación de parámetros, que también se ofrece en PDO.
PDO es una librería de abstracción de conexión a bases de datos — incorporada en PHP desde 5.1.0 — que proporciona una interfaz común común para hablar con muchas bases de datos diferentes. Por ejemplo, puede utilizar código básicamente idéntico para interactuar con MySQL o SQLite:
<?php
// PDO + MySQL
$pdo = new PDO('mysql:host=example.com;dbname=database', 'user', 'password');
$statement = $pdo->query("SELECT some_field FROM some_table");
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo htmlentities($row['some_field']);
// PDO + SQLite
$pdo = new PDO('sqlite:/path/db/foo.sqlite');
$statement = $pdo->query("SELECT some_field FROM some_table");
$row = $statement->fetch(PDO::FETCH_ASSOC);
echo htmlentities($row['some_field']);
PDO no traducirá sus consultas SQL o emulará las características que faltan; es puramente para la conexión a múltiples tipos de base de datos con la misma API.
Y lo que es más importante, PDO
le permite inyectar de forma segura entradas ajenas (por ejemplo, IDs) en sus consultas SQL sin preocuparse
por ataques de inyección SQL a bases de datos.
Esto es posible utilizando sentencias PDO y parámetros vinculados.
Supongamos que un script PHP recibe un ID numérico como parámetro de consulta. Este ID debe ser usado para obtener un registro
de usuario de una base de datos. Esta es la forma incorrecta
de hacer esto:
<?php
$pdo = new PDO('sqlite:/path/db/users.db');
$pdo->query("SELECT name FROM users WHERE id = " . $_GET['id']); // <-- NO!
Este código es terrible. Estás insertando un parámetro de consulta sin procesar en una consulta SQL. Esto hará que te hackeen en un santiamén, usando una práctica llamada Inyección SQL. Imagínese si un hacker pasa un parámetro id
inventivo
llamando a una URL como http://domain.com/?id=1%3BDELETE+FROM+users
. Esto establecerá la variable $_GET['id']
a
1;DELETE FROM users
lo que borrará todos los usuarios. En su lugar, debería desinfectar/sanitizar la entrada de ID utilizando
parámetros vinculados a PDO.
<?php
$pdo = new PDO('sqlite:/path/db/users.db');
$stmt = $pdo->prepare('SELECT name FROM users WHERE id = :id');
$id = filter_input(INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT); // <-- filtre primero los datos (ver [Filtrado de Datos](#filtrado_de_datos)), especialmente importante para INSERT, UPDATE, etc.
$stmt->bindParam(':id', $id, PDO::PARAM_INT); // <-- SQL saneado automáticamente por PDO
$stmt->execute();
Este código es correcto. Utiliza un parámetro vinculado en una sentencia PDO. Esto escapa el ID de entrada externo antes de que sea introducido en la base de datos previniendo potenciales ataques de inyección SQL.
Para escrituras, como INSERT o UPDATE, es especialmente crítico filtrar sus datos primero y sanearlos para otras cosas (eliminación de etiquetas HTML, JavaScript, etc). PDO sólo lo desinfectará para SQL, no para su aplicación.
También hay que tener en cuenta que las conexiones a bases de datos consumen recursos y no era raro que se agotaran los recursos si las conexiones no se cerraban implícitamente, aunque esto era más común en otros lenguajes. Usando PDO puedes cerrar implícitamente la conexión destruyendo el objeto asegurándote de que todas las referencias restantes a él son borradas, es decir, establecidas a NULL. Si no hace esto explícitamente, PHP cerrará automáticamente la conexión cuando su script termine - a menos que esté usando conexiones persistentes.
Cuando los desarrolladores comienzan a aprender PHP, a menudo terminan mezclando su interacción con la base de datos con su lógica de presentación, utilizando código que podría parecerse a esto:
<ul>
<?php
foreach ($db->query('SELECT * FROM table') as $row) {
echo "<li>".$row['field1']." - ".$row['field1']."</li>";
}
?>
</ul>
Esta es una mala práctica por todo tipo de razones, principalmente que es difícil de depurar, difícil de probar, difícil de leer y que va a dar salida a un montón de campos si no pones un límite.
Aunque hay muchas otras soluciones para hacer esto - dependiendo de si prefieres POO o programación funcional - debe haber algún elemento de separación.
Considere el paso más básico:
<?php
function getAllFoos($db) {
return $db->query('SELECT * FROM table');
}
$results = getAllFoos($db);
foreach ($results as $row) {
echo "<li>".$row['field1']." - ".$row['field1']."</li>"; // BAD!!
}
Es un buen comienzo. Pon esos dos elementos en dos archivos diferentes y tendrás una separación limpia.
Crea una clase en la que colocar ese método y tendrás un “Modelo”. Crea un simple archivo .php
para colocar
la lógica de presentación y tendrás una “Vista”, que es muy parecido a MVC - una arquitectura OOP común para
la mayoría de los frameworks.
foo.php
<?php
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8mb4', 'username', 'password');
// Ponga su modelo a disposición
include 'models/FooModel.php';
// Crear una instancia
$fooModel = new FooModel($db);
// Obtener la lista de Foos
$fooList = $fooModel->getAllFoos();
// Mostrar la vista
include 'views/foo-list.php';
models/FooModel.php
<?php
class FooModel
{
public function __construct(protected PDO $db)
{
}
public function getAllFoos() {
return $this->db->query('SELECT * FROM table');
}
}
views/foo-list.php
<?php foreach ($fooList as $row): ?>
<li><?= $row['field1'] ?> - <?= $row['field1'] ?></li>
<?php endforeach ?>
Esto es esencialmente lo mismo que hacen la mayoría de los frameworks modernos, aunque un poco más manual. Puede que no necesites hacer todo eso cada vez, pero mezclar demasiada lógica de presentación e interacción con la base de datos puede ser un verdadero problema si alguna vez quieres hacer test unitarios a tu aplicación.
Muchos frameworks proporcionan su propia capa de abstracción que puede o no sentarse encima de PDO. Estos a menudo emulan características de un sistema de base de datos que falta en otro envolviendo sus consultas en métodos PHP, dándole abstracción de base de datos real en lugar de sólo la abstracción de conexión que PDO proporciona. Esto, por supuesto, añadirá un poco de sobrecarga, pero si usted está construyendo una aplicación portable que necesita trabajar con MySQL, PostgreSQL y SQLite entonces un poco de sobrecarga valdrá la pena por el bien de la limpieza del código.
Algunas capas de abstracción se han construido utilizando los estándares de espacio de nombres PSR-0 o PSR-4, por lo que pueden instalarse en cualquier aplicación que se desee:
Las Plantillas proporcionan una manera conveniente de separar la lógica de tu controlador y dominio de tu lógica de presentación. Las plantillas suelen contener el código HTML de tu aplicación, pero también se pueden utilizar otros formatos, como XML. A menudo se hace referencia a las plantillas como “vistas”, las cuales forman parte del segundo componente del patrón de arquitectura de software modelo-vista-controlador (MVC).
El principal beneficio de utilizar plantillas es la clara separación que crean entre la lógica de presentación y el resto de tu aplicación. Las plantillas tienen la única responsabilidad de mostrar contenido formateado. No son responsables de la búsqueda de datos, la persistencia u otras tareas más complejas. Esto lleva a un código más limpio y más legible, lo cual es especialmente útil en un entorno de equipo donde los desarrolladores trabajan en el código del lado del servidor (controladores, modelos) y los diseñadores trabajan en el código del lado del cliente (maquetado).
Las plantillas también mejoran la organización del código de presentación. Por lo general, las plantillas se colocan en una carpeta de “vistas” (“views”), cada una definida en un solo archivo. Este enfoque fomenta la reutilización del código, donde bloques más grandes de código se dividen en piezas más pequeñas y reutilizables, a menudo llamadas parciales (partials). Por ejemplo, el encabezado y el pie de página de tu sitio pueden definirse como plantillas, las cuales se incluyen antes y después de cada plantilla de página.
Finalmente, dependiendo de la biblioteca que uses, las plantillas pueden ofrecer más seguridad al escapar automáticamente el contenido generado por los usuarios. Algunas bibliotecas incluso ofrecen un sistema de “sand-boxing”, donde los diseñadores de plantillas solo tienen acceso a variables y funciones en una lista blanca.
Las plantillas en PHP simple son simplemente plantillas que utilizan código PHP nativo. Son una opción natural ya que PHP es, de hecho, un lenguaje de plantillas. Esto significa que puedes combinar código PHP con otro código, como HTML. Esto es beneficioso para los desarrolladores de PHP ya que no hay nueva sintaxis que aprender, conocen las funciones disponibles y sus editores de código ya tienen resaltado de sintaxis y autocompletado incorporado. Además, las plantillas en PHP simple tienden a ser muy rápidas, ya que no se requiere una etapa de compilación.
Todos los frameworks modernos de PHP emplean algún tipo de sistema de plantillas, la mayoría de los cuales utilizan PHP simple por defecto. Fuera de los frameworks, bibliotecas como Plates o Aura.View facilitan el trabajo con plantillas en PHP simple al ofrecer funcionalidades modernas de plantillas, como herencia, layouts y extensiones.
Usando la biblioteca Plates.
<?php // user_profile.php ?>
<?php $this->insert('header', ['title' => 'User Profile']) ?>
<h1>User Profile</h1>
<p>Hello, <?=$this->escape($name)?></p>
<?php $this->insert('footer') ?>
Haciendo uso de la biblioteca Plates.
<?php // template.php ?>
<html>
<head>
<title><?=$title?></title>
</head>
<body>
<main>
<?=$this->section('content')?>
</main>
</body>
</html>
<?php // user_profile.php ?>
<?php $this->layout('template', ['title' => 'User Profile']) ?>
<h1>User Profile</h1>
<p>Hello, <?=$this->escape($name)?></p>
Aunque PHP ha evolucionado hasta convertirse en un lenguaje maduro, orientado a objetos, no ha mejorado mucho como lenguaje de plantillas. Las plantillas compiladas, como Twig, Brainy o Smarty*, llenan este vacío al ofrecer una nueva sintaxis diseñada específicamente para la creación de plantillas. Desde el escape automático hasta la herencia y estructuras de control simplificadas, las plantillas compiladas están diseñadas para ser más fáciles de escribir, más legibles y más seguras de usar. Las plantillas compiladas incluso pueden compartirse entre diferentes lenguajes, siendo Mustache un buen ejemplo de esto. Dado que estas plantillas deben ser compiladas, hay una ligera pérdida de rendimiento, sin embargo, esto es muy mínimo cuando se utiliza un sistema de caché apropiado.
*Aunque Smarty ofrece escape automático, NO está habilitado por defecto.
Haciendo uso de Twig.
{% include 'header.html' with {'title': 'User Profile'} %}
<h1>User Profile</h1>
<p>Hello, {{ name }}</p>
{% include 'footer.html' %}
Usando Twig.
// template.html
<html>
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<main>
{% block content %}{% endblock %}
</main>
</body>
</html>
// user_profile.html
{% extends "template.html" %}
{% block title %}User Profile{% endblock %}
{% block content %}
<h1>User Profile</h1>
<p>Hello, {{ name }}</p>
{% endblock %}
En muchos lenguajes de programación “dependientes de excepciones”, cada vez que algo sale mal, se lanzará una excepción. Esta es una forma viable de manejar errores, pero PHP es un lenguaje “ligero en excepciones”. Aunque tiene excepciones y cada vez más partes del núcleo las usan cuando se trabaja con objetos, la mayoría de PHP intentará seguir procesando sin importar lo que suceda, a menos que ocurra un error fatal.
Por ejemplo:
$ php -a
php > echo $foo;
Notice: Undefined variable: foo in php shell code on line 1
Esto es solo un aviso, y PHP continuará felizmente. Esto puede ser confuso para aquellos que vienen de lenguajes “dependientes de excepciones”, porque en Python, por ejemplo, hacer referencia a una variable no definida lanzará una excepción:
$ python
>>> print foo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined
La única diferencia real es que Python reaccionará a cualquier pequeño problema, de manera que los desarrolladores puedan estar muy seguros de que cualquier posible problema o caso límite sea detectado, mientras que PHP seguirá procesando a menos que suceda algo extremo, en cuyo caso lanzará un error y lo reportará.
PHP tiene varios niveles de gravedad de errores. Los tres tipos más comunes de mensajes son errores, avisos y
advertencias. Estos tienen diferentes niveles de severidad: E_ERROR
, E_NOTICE
, y E_WARNING
.
Los errores son fallos fatales en tiempo de ejecución y usualmente son causados por fallos en tu código que deben ser
corregidos, ya que harán que PHP deje de ejecutarse. Los avisos son mensajes de carácter informativo causados por
código que puede o no causar problemas durante la ejecución del script, pero la ejecución no se detiene.
Las advertencias son errores no fatales, y la ejecución del script no se detendrá.
Otro tipo de mensaje de error reportado en tiempo de compilación son los mensajes E_STRICT
.
Estos mensajes se utilizan para sugerir cambios en tu código para ayudar a garantizar la mejor interoperabilidad y
compatibilidad con futuras versiones de PHP.
El reporte de errores se puede cambiar utilizando configuraciones de PHP y/o llamadas a funciones de PHP.
Usando la función incorporada error_reporting()
, puedes establecer el nivel de errores durante la ejecución del script
pasando una de las constantes predefinidas de nivel de error. Por ejemplo, si solo quieres ver Errores y Advertencias,
pero no Avisos (Notices), puedes configurarlo así:
<?php
error_reporting(E_ERROR | E_WARNING);
También puedes controlar si los errores se muestran en pantalla (útil en desarrollo) o si se ocultan y registran (útil en producción). Para más información, revisa la sección de Reporte de Errores.
También puedes decirle a PHP que suprima errores específicos usando el Operador de Control de Errores @
.
Pones este operador al inicio de una expresión, y cualquier error que sea resultado directo de la expresión se silenciará.
<?php
echo @$foo['bar'];
Esto imprimirá $foo['bar']
si existe, pero simplemente devolverá nulo y no mostrará nada si la variable $foo
o la
clave 'bar'
no existen. Sin el operador de control de errores, esta expresión podría crear un error
PHP Notice: Undefined variable: foo
o PHP Notice: Undefined index: bar
.
Esto podría parecer una buena idea, pero hay algunas desventajas indeseables. PHP maneja expresiones con un @
de una
manera menos eficiente que expresiones sin el @
. La optimización prematura puede ser la raíz de todas las discusiones
de programación, pero si el rendimiento es particularmente importante para tu aplicación/biblioteca, es importante
entender las implicaciones de rendimiento del operador de control de errores.
En segundo lugar, el operador de control de errores suprime completamente el error. El error no se muestra y no se envía al registro de errores. Además, los sistemas PHP estándar/producción no tienen forma de desactivar el operador de control de errores. Aunque puede que tengas razón al considerar que el error que estás viendo es inofensivo, un error diferente y menos inofensivo será igual de silencioso.
Si hay una forma de evitar el uso del operador de supresión de errores, deberías considerarla. Por ejemplo, nuestro código anterior podría reescribirse de la siguiente manera:
<?php
// Null Coalescing Operator
echo $foo['bar'] ?? '';
Un caso donde podría tener sentido suprimir un error es cuando fopen()
falla al encontrar un archivo. Podrías
verificar la existencia del archivo antes de intentar cargarlo, pero si el archivo se elimina después de la verificación
y antes de la llamada a fopen()
(lo cual puede parecer imposible, pero puede ocurrir), entonces fopen()
devolverá
falso y lanzará un error. Esto es algo que PHP debería resolver, pero es un caso donde la supresión de errores podría
parecer la única solución válida.
Mencionamos antes que no hay forma en un sistema PHP estándar de desactivar el operador de control de errores. Sin
embargo, Xdebug tiene una configuración xdebug.scream
en el archivo ini
que deshabilitará el operador de control
de errores. Puedes configurarlo en tu archivo php.ini
de la siguiente manera:
xdebug.scream = On
También puedes establecer este valor en tiempo de ejecución con la función ini_set
<?php
ini_set('xdebug.scream', '1')
Esto es muy útil cuando estás depurando código y sospechas que un error informativo está siendo suprimido. Usa scream con cuidado y como una herramienta temporal de depuración. Hay mucho código de bibliotecas PHP que puede no funcionar con el operador de control de errores deshabilitado.
PHP es perfectamente capaz de ser un lenguaje de programación “dependiente de excepciones” y solo requiere unas pocas
líneas de código para hacer el cambio. Básicamente, puedes lanzar tus “errores” como “excepciones” usando la clase
ErrorException
, que extiende la clase Exception
.
Esta es una práctica común implementada por un gran número de frameworks modernos como Symfony y Laravel. En modo de depuración (o modo dev), ambos frameworks mostrarán una stack trace limpia y agradable.
También hay algunos paquetes disponibles para un mejor manejo y reporte de errores y excepciones, como Whoops!, que viene con la instalación predeterminada de Laravel y puede usarse en cualquier framework.
Al lanzar errores como excepciones durante el desarrollo, puedes manejarlos mejor que con el resultado habitual, y si ves una excepción durante el desarrollo, puedes envolverla en una declaración de captura con instrucciones específicas sobre cómo manejar la situación. Cada excepción que captures hace que tu aplicación sea un poco más robusta.
Más información sobre esto y detalles sobre cómo usar ErrorException
con el manejo de errores se pueden encontrar en
la Clase ErrorException.
Las excepciones son una parte estándar de la mayoría de los lenguajes de programación populares, pero a menudo son pasadas por alto por los programadores de PHP. Lenguajes como Ruby son extremadamente dependientes de excepciones, así que cada vez que algo sale mal, como una falla en una solicitud HTTP, un error en una consulta a la base de datos, o incluso si no se puede encontrar un recurso de imagen, Ruby (o las gems utilizadas) lanzará una excepción a la pantalla, lo que significa que instantáneamente sabrás que hay un error.
PHP, por su parte, es bastante indulgente con esto, y una llamada a file_get_contents()
generalmente solo te devolverá
un FALSE
y un warning
. Muchos frameworks antiguos de PHP, como CodeIgniter, simplemente devolverán un falso,
registrarán un mensaje en sus registros y tal vez te permitan usar un método como $this->upload->get_error() para ver
qué salió mal. El problema aquí es que tienes que ir a buscar un error y consultar la documentación para ver cuál es
el método de error para esta clase, en lugar de que se te haga extremadamente obvio.
Otro problema es cuando las clases lanzan automáticamente un error en la pantalla y terminan el proceso. Cuando haces esto, detienes a otro desarrollador de poder manejar dinámicamente ese error. Las excepciones deben lanzarse para hacer que un desarrollador sea consciente de un error; luego puede elegir cómo manejarlo. Por ejemplo:
<?php
$email = new Fuel\Email;
$email->subject('My Subject');
$email->body('How the heck are you?');
$email->to('guy@example.com', 'Some Guy');
try
{
$email->send();
}
catch(Fuel\Email\ValidationFailedException $e)
{
// La validación falló
}
catch(Fuel\Email\SendingFailedException $e)
{
// El controlador no pudo enviar el correo electrónico
}
finally
{
// Ejecutado independientemente de si se ha lanzado una excepción, y antes de que se reanude la ejecución normal
}
La clase genérica Exception
proporciona muy poco contexto de depuración para el desarrollador; sin embargo,
para remediar esto, es posible crear un tipo de Exception
especializado al sub-clasificar la clase genérica Exception
:
<?php
class ValidationException extends Exception {}
Esto significa que puedes agregar múltiples bloques de captura y manejar diferentes excepciones de manera diferente. Esto puede llevar a la creación de un gran número de Excepciones personalizadas, algunas de las cuales podrían haberse evitado utilizando las excepciones SPL proporcionadas en la extensión SPL.
Si, por ejemplo, utilizas el método mágico __call()
y se solicita un método no válido, en lugar de lanzar una
Excepción estándar que es vaga, o crear una Excepción personalizada solo para eso,
podrías simplemente throw new BadMethodCallException;
.
El mejor recurso que he encontrado sobre seguridad en PHP es The 2018 Guide to Building Secure PHP Software por Paragon Initiative.
Es muy importante que todo desarrollador PHP aprenda los fundamentos de la seguridad de las aplicaciones web, que pueden dividirse en un puñado de temas generales:
Hay gente mala lista y dispuesta a explotar su aplicación web. Es importante que tome las precauciones necesarias para reforzar la seguridad de su aplicación web. Por suerte, la buena gente de The Open Web Application Security Project (OWASP) ha recopilado una lista exhaustiva de problemas de seguridad conocidos y métodos para protegerse contra ellos. Se trata de una lectura obligatoria para los desarrolladores preocupados por la seguridad. Survive The Deep End: PHP Security de Padraic Brady es también otra buena guía de seguridad de aplicaciones web para PHP.
Al final, todo el mundo crea una aplicación PHP que depende del inicio de sesión del usuario. Los nombres de usuario y las contraseñas se almacenan en una base de datos y luego se utilizan para autenticar a los usuarios al iniciar sesión.
Es importante hacer hash correctamente a las contraseñas antes de almacenarlas. Hacer un hash y cifrar son dos cosas muy diferentes que a menudo se confunden.
El hashing es una función irreversible y unidireccional. Produce una cadena de longitud fija que no se puede invertir. Esto significa que se puede comparar un hash con otro para determinar si ambos proceden de la misma cadena de origen, pero no se puede determinar la cadena original a partir del hash. Si las contraseñas no tienen hash y un tercero no autorizado accede a la base de datos, todas las cuentas de usuario estarán en peligro.
A diferencia del hashing, el cifrado es reversible (siempre que se tenga la clave). El cifrado es útil en otros ámbitos, pero es una mala estrategia para almacenar contraseñas de forma segura.
Las contraseñas también deben ser salados (del inglés “salted”) individualmente, añadiendo una cadena aleatoria a cada contraseña antes de aplicar el hash. Así se evitan los ataques de diccionario y el uso de “tablas arco iris” (una lista inversa de hashes criptográficos para contraseñas comunes).
El hashing y el salting son vitales, ya que a menudo los usuarios utilizan la misma contraseña para varios servicios y la calidad de las contraseñas puede ser deficiente.
Además, debe utilizar un algoritmo especializado de password hashing en lugar de una función hash criptográfica rápida de uso general (por ejemplo, SHA256). La lista corta de algoritmos hash de contraseña aceptables (a junio de 2018) para usar son:
Afortunadamente, hoy en día PHP facilita esta tarea.
Hashear contraseñas con password_hash
En PHP 5.5 se introdujo password_hash()
. En este momento usa BCrypt, el algoritmo más fuerte actualmente soportado por PHP.
Sin embargo, será actualizado en el futuro para soportar más algoritmos según sea necesario.
La librería password_compat
fue creada para proporcionar compatibilidad con PHP >= 5.3.7.
A continuación, hacemos un hash de una cadena y lo comparamos con una nueva cadena. Debido a que nuestras dos cadenas de origen son diferentes (‘secret-password’ vs. ‘bad-password’) este login fallará.
<?php
require 'password.php';
$passwordHash = password_hash('secret-password', PASSWORD_DEFAULT);
if (password_verify('bad-password', $passwordHash)) {
// Contraseña correcta
} else {
// Contraseña inválida
}
password_hash()
se encarga del salado de contraseñas por ti. La sal se almacena, junto con el algoritmo y el “coste”, como parte del hash.
password_verify()
extrae esto para determinar cómo comprobar la contraseña, por lo que no necesitas un campo de base de datos separado para almacenar tus sales.
Nuca (nunca) confíes en la introducción de datos ajenos en tu código PHP. Siempre sanee y valide la entrada ajena antes
de usarla en el código. Las funciones filter_var()
y filter_input()
pueden sanear texto y validar formatos de texto
(por ejemplo, direcciones de correo electrónico).
La entrada ajena puede ser cualquier cosa: datos de formulario $_GET
y $_POST
, algunos valores en el superglobal $_SERVER
,
y el cuerpo de la petición HTTP a través de fopen('php://input', 'r')
. Recuerde, la entrada de datos externos
no se limita a los datos del formulario enviados por el usuario. Los archivos cargados y descargados, los valores de sesión,
los datos de cookies y los datos de servicios web de terceros también son entradas de datos externos.
Aunque la introducción de datos ajenos pueden almacenarse, combinarse y accederse posteriormente, siguen siendo entrada ajena. Cada vez que proceses, des salida, concatenes o incluyas datos en tu código, pregúntate si los datos están filtrados correctamente y si son de confianza.
Los datos pueden filtrarse de forma diferente en función de su finalidad. Por ejemplo, cuando una entrada ajena no filtrada
se pasa a la salida de una página HTML, ¡puede ejecutar HTML y JavaScript en su sitio! Esto se conoce como Cross-Site Scripting (XSS)
y puede ser un ataque muy peligroso. Una forma de evitar XSS es desinfectar todos los datos generados por el usuario antes de enviarlos
a la página eliminando las etiquetas HTML con la función strip_tags()
o escapando caracteres con significado especial
en sus respectivas entidades HTML con las funciones htmlentities()
o htmlspecialchars()
.
Otro ejemplo es pasar opciones para ser ejecutadas en la línea de comandos. Esto puede ser extremadamente peligroso (y suele ser una mala idea),
pero puede utilizar la función integrada escapeshellarg()
para desinfectar los argumentos del comando ejecutado.
Un último ejemplo es aceptar una entrada extraña para determinar un fichero a cargar del sistema de ficheros. Esto puede
ser explotado cambiando el nombre del archivo a una ruta de archivo. Es necesario eliminar "/"
, "../"
,
bytes nulos, u otros caracteres de la ruta del archivo para que no pueda cargar archivos ocultos, no públicos o sensibles.
filter_var
filter_input
La sanitización elimina (o escapa) caracteres ilegales o inseguros de los datos de entrada ajenos.
Por ejemplo, debe desinfectar los datos de entrada ajenos antes de incluirla en HTML o insertarla en una consulta SQL sin procesar. Cuando use parámetros vinculados con PDO, se limpiarán los datos de entrada por usted.
A veces es necesario permitir algunas etiquetas HTML seguras en los datos de entrada al incluirla en la página HTML. Esto es muy difícil de hacer y muchos lo evitan usando otros formatos más restringidos como Markdown o BBCode, aunque para ello existen librerías de filtrado de datos como HTML Purifier.
Es peligroso deserializar datos de usuarios u otras fuentes no confiables utilizando unserialize()
.
Hacerlo puede permitir a usuarios maliciosos instanciar objetos (con propiedades definidas por el usuario) cuyos destructores serán ejecutados,
incluso si los propios objetos no son utilizados. Por lo tanto, debes evitar deserializar datos que no sean de confianza.
Utiliza un formato de intercambio de datos seguro y estándar como JSON (a través de json_decode
y json_encode
) si necesitas pasar datos serializados al usuario.
La validación garantiza que la entrada de datos ajenos es la esperada. Por ejemplo, es posible que desee validar una dirección de correo electrónico, un número de teléfono o la edad al procesar un envío de registro.
Al crear archivos de configuración para sus aplicaciones, las mejores prácticas recomiendan que se siga uno de los siguientes métodos siguientes:
.php
. Esto garantiza que,
aunque se acceda directamente al script, no se mostrará como texto sin formato.NOTA: A partir de PHP 5.4.0 el parámetro register_globals
ha sido eliminado y ya no puede ser usado.
Esto sólo se incluye como una advertencia para cualquier persona en el proceso de actualización de una aplicación de legado.
Cuando está activada, la configuración register_globals
hace que varios tipos de variables (incluyendo las de $_POST
,
$_GET
y $_REQUEST
) estén disponibles en el ámbito global de tu aplicación. Esto puede llevar
fácilmente a problemas de seguridad ya que tu aplicación no puede saber de dónde vienen los datos.
Por ejemplo: $_GET['foo']
estaría disponible a través de $foo
, lo cual puede anular variables que hayan sido declaradas.
Si estás usando PHP < 5.4.0 asegúrate de que register_globals
está desactivado.
El registro de errores puede ser útil para encontrar los puntos problemáticos en su aplicación, pero también puede exponer información sobre la estructura de su aplicación al mundo exterior. Para proteger eficazmente su aplicación de los problemas que podrían ser causados por la salida de estos mensajes, es necesario configurar el servidor de manera diferente en el desarrollo frente a la producción (en vivo).
Para mostrar todos los errores posibles durante el desarrollo, configure los siguientes parámetros en su php.ini
:
display_errors = On
display_startup_errors = On
error_reporting = -1
log_errors = On
Pasando el valor
-1
se mostrarán todos los errores posibles, incluso cuando se añadan nuevos niveles y constantes en futuras versiones de PHP. La constanteE_ALL
también se comporta de esta manera a partir de PHP 5.4. - php.net
La constante de nivel de error E_STRICT
se introdujo en 5.3.0 y no forma parte de E_ALL
, sin embargo pasó a
formar parte de E_ALL
en 5.4.0. ¿Qué significa esto? En términos de informar de todos los errores posibles en la versión 5.3
significa que debe utilizar -1
o E_ALL | E_STRICT
.
Informar de todos los errores posibles por versión de PHP
-1
o E_ALL
-1
o E_ALL | E_STRICT
-1
o E_ALL
Para ocultar los errores en su entorno de producción, configure su php.ini
así:
display_errors = Off
display_startup_errors = Off
error_reporting = E_ALL
log_errors = On
Con esta configuración en producción, los errores seguirán registrándose en los registros de errores del servidor web, pero no se mostrarán al usuario. Para más información sobre estos ajustes, consulte el manual de PHP:
Escribir pruebas automatizadas para su código PHP se considera una buena práctica y puede conducir a aplicaciones bien construidas. Las pruebas automatizadas son una gran herramienta para asegurarse de que su aplicación no se rompe cuando usted está haciendo cambios o añadiendo nuevas funcionalidades y no debe ser ignorada.
Existen varios tipos de herramientas de pruebas (o frameworks) disponibles para PHP, que utilizan diferentes enfoques - todos los cuales tratan de evitar las pruebas manuales y la necesidad de grandes equipos de Aseguramiento de la Calidad (QA, por sus siglas en inglés), sólo para asegurarse de que los cambios recientes no rompen la funcionalidad existente.
De Wikipedia:
El desarrollo dirigido por pruebas (TDD, por sus siglas en inglés) es un proceso de desarrollo de software que se basa en la repetición de un ciclo de desarrollo muy corto: primero, el desarrollador escribe un caso de prueba automatizado que falla y que define una mejora deseada o una nueva función; después, produce código para superar esa prueba y, por último, refactoriza el nuevo código para que cumpla unos estándares aceptables. Kent Beck, a quien se atribuye haber desarrollado o “redescubierto” la técnica, declaró en 2003 que el TDD fomenta los diseños sencillos e inspira confianza.
Hay varios tipos diferentes de pruebas que puede realizar para su aplicación:
Las pruebas unitarias son un enfoque de programación para garantizar que las funciones, clases y métodos funcionan como se espera, desde el momento en que se construyen hasta el final del ciclo de desarrollo. Comprobando los valores que entran y salen de varias funciones y métodos, puedes asegurarte de que la lógica interna funciona correctamente. Mediante el uso de la inyección de dependencias y la creación de clases y stubs “simulados”, puede comprobar que las dependencias se utilizan correctamente para mejorar aún más la cobertura de las pruebas.
Cuando creas una clase o función deberías crear una prueba unitaria para cada comportamiento que deba tener. A un nivel muy básico
deberías asegurarte de que da error si le envías argumentos erróneos y asegurarte de que funciona si le envías argumentos válidos.
Esto ayudará a asegurar que cuando hagas cambios a esta clase o función más adelante en el ciclo de desarrollo, la funcionalidad antigua
siga funcionando como se esperaba. La única alternativa a esto sería var_dump()
en un test.php, que no es forma de construir
una aplicación - grande o pequeña.
La otra utilidad de las pruebas unitarias es contribuir al código abierto. Si puedes escribir una prueba que muestre una funcionalidad rota (es decir, que falla), luego arreglarla, y mostrar que la prueba pasa, es mucho más probable que los parches sean aceptados. Si diriges un proyecto que acepta pull requests, deberías sugerirlo como requisito.
PHPUnit PHPUnit es el marco de pruebas de facto para escribir pruebas unitarias para aplicaciones PHP, pero existen varias alternativas:
De Wikipedia:
Las pruebas de integración (a veces denominadas integración y pruebas, abreviadas “I&T”) son la fase de las pruebas de software en la que se combinan módulos de software individuales y se prueban como un grupo. Se realiza después de las pruebas unitarias y antes de las de validación. Las pruebas de integración toman como entrada los módulos que se han probado por unidades, los agrupan en conjuntos más grandes, aplican a esos conjuntos las pruebas definidas en un plan de pruebas de integración y entregan como salida el sistema integrado listo para las pruebas del sistema.
Muchas de las mismas herramientas que pueden utilizarse para las pruebas unitarias pueden emplearse para las pruebas de integración, ya que se utilizan muchos de los mismos principios.
A veces también conocidas como pruebas de aceptación, las pruebas funcionales consisten en utilizar herramientas para crear pruebas automatizadas que realmente utilizan la aplicación, en lugar de limitarse a verificar que las unidades individuales de código se comportan correctamente y que las unidades individuales pueden hablar entre sí correctamente. Estas herramientas suelen funcionar utilizando datos reales y simulando usuarios reales de la aplicación.
Existen dos tipos diferentes de Desarrollo Guiado por Comportamiento (BDD): SpecBDD y StoryBDD. SpecBDD se centra en el comportamiento técnico del código, mientras que StoryBDD se centra en los comportamientos o interacciones del negocio o de las características. PHP tiene frameworks para ambos tipos de BDD.
Con StoryBDD, se escriben historias legibles que describen el comportamiento de la aplicación. Estas historias se pueden ejecutar como pruebas reales contra su aplicación. El framework utilizado en aplicaciones PHP para StoryBDD es Behat, que está inspirado en el proyecto Cucumber de Ruby e implementa el DSL Gherkin para describir el comportamiento de las características.
Con SpecBDD, se escriben especificaciones que describen cómo debe comportarse el código real. En lugar de probar una función o método, usted está describiendo cómo esa función o método debe comportarse. PHP ofrece el framework PHPSpec para este propósito. Este framework está inspirado en el proyecto RSpec para Ruby.
Además de las pruebas individuales y los marcos orientados al comportamiento, también hay una serie de marcos genéricos y bibliotecas de ayuda útiles para cualquier enfoque preferido.
Las aplicaciones PHP se pueden desplegar y correr en servidores web de producción de multiples maneras.
Una PaaS (Platform as a Service) proporciona la arquitectura de sistema y de red necesaria para ejecutar aplicaciones PHP en la web. Esto significa que se requiere poca o ninguna configuración para lanzar aplicaciones PHP o frameworks de PHP.
Recientemente, PaaS se ha convertido en un método popular para desplegar, alojar y escalar aplicaciones PHP de todos los tamaños. Puedes encontrar una lista de proveedores PaaS para PHP en nuestra sección de recursos.
Si te sientes cómodo con la administración de sistemas, o estás interesado en aprender, los servidores virtuales o dedicados te permiten tener control total sobre el entorno de producción de tu aplicación.
PHP, con el gestor de procesos FastCGI (FastCGI Process Manager, FPM por sus siglas en inglés) integrado en PHP, se complementa muy bien con nginx, el cual es un servidor web ligero y de alto rendimiento. Utiliza menos memoria que Apache y puede manejar mejor más solicitudes concurrentes. Esto es especialmente importante en servidores virtuales que no tienen mucha memoria disponible.
PHP y Apache tienen una larga historia juntos. Apache es ampliamente configurable y cuenta con muchos módulos disponibles para extender su funcionalidad. Es una elección común para servidores compartidos y una configuración sencilla para frameworks PHP y aplicaciones de código abierto como WordPress. Desafortunadamente, Apache por defecto utiliza más recursos que nginx y no puede manejar tantos visitantes al mismo tiempo.
Apache posee varias configuraciones posibles para ejecutar PHP. La más común y más fácil de configurar es el prefork MPM
con mod_php
. Aunque no es la más eficiente en términos de memoria, es la más sencilla de hacer funcionar y utilizar.
Probablemente sea la mejor opción si no deseas profundizar demasiado en los aspectos de administración del servidor.
Ten en cuenta que si usas mod_php
DEBES usar el prefork MPM.
Alternativamente, si quieres sacar más rendimiento y estabilidad de Apache, puedes aprovechar el mismo sistema FPM que
nginx y ejecutar el worker MPM o el event MPM con mod_fastcgi
o mod_fcgid
. Esta configuración será significativamente
más eficiente en memoria y mucho más rápida, pero requiere más trabajo para configurarla.
Si estás ejecutando Apache 2.4 o posterior, puedes usar mod_proxy_fcgi para obtener un gran rendimiento y es fácil de configurar.
PHP debe su popularidad a los servidores compartidos. Es difícil encontrar un hosting sin PHP instalado, pero asegúrate de que sea la última versión. Los servidores compartidos permiten que tú y otros desarrolladores puedan desplegar sitios web en una sola máquina. La ventaja de esto es que se ha convertido en una mercancía barata. La desventaja es que nunca sabes qué tipo de problemas pueden causar tus vecinos; sobrecargar el servidor o abrir agujeros de seguridad son las principales preocupaciones. Si el presupuesto de tu proyecto puede permitirse evitar los servidores compartidos, deberías hacerlo.
Asegúrate de que tus servidores compartidos ofrezcan las últimas versiones de PHP.
Si te encuentras haciendo cambios manuales en el esquema de la base de datos o ejecutando tus pruebas manualmente antes de actualizar tus archivos (manualmente), ¡piénsalo dos veces! Con cada tarea manual adicional necesaria para desplegar una nueva versión de tu aplicación, las posibilidades de cometer errores potencialmente fatales aumentan. Ya sea que estés lidiando con una actualización simple, un proceso de compilación más complejo o incluso una estrategia de integración continua, la automatización es tu aliada.
Estas son las tareas que podrías querer automatizar:
Las herramientas de despliegue se pueden describir como una colección de scripts que llevan a cabo tareas comunes de despliegue de software. La herramienta de despliegue no es parte de tu software, actúa sobre tu software desde ‘afuera’.
Existen muchas herramientas de código abierto disponibles para ayudarte con la automatización de compilación y despliegue, algunas están escritas en PHP y otras no. Esto no debería impedirte usarlas si son más adecuadas para ese trabajo específico. Aquí tienes algunos ejemplos:
Phing puede controlar tu proceso de empaquetado, despliegue o pruebas desde un archivo XML. Phing (basado en Apache Ant) proporciona un conjunto completo de tareas que usualmente se necesitan para instalar o actualizar una aplicación web y se puede extender con tareas personalizadas adicionales, escritas en PHP. Es una herramienta sólida y robusta que ha estado presente durante mucho tiempo, sin embargo, podría percibirse como una herramienta un poco anticuada debido a la forma en que maneja la configuración (archivos XML).
Capistrano es un sistema para programadores intermedios a avanzados que permite ejecutar comandos de manera estructurada y repetible en una o más máquinas remotas. Está preconfigurado para desplegar aplicaciones Ruby on Rails, sin embargo, también puedes desplegar sistemas PHP sin problemas. El uso exitoso de Capistrano depende de un conocimiento práctico de Ruby y Rake.
Ansistrano es un grupo de roles de Ansible para gestionar fácilmente el proceso de despliegue (despliegue y reversión) de aplicaciones de scripting como PHP, Python y Ruby. Es un port de Ansible para Capistrano. Ya ha sido utilizado por muchas empresas de PHP.
Deployer es una herramienta de despliegue escrita en PHP. Es simple y funcional. Sus características incluyen ejecución de tareas en paralelo, despliegue atómico y mantener de la consistencia entre servidores. Dispone recetas de tareas comunes para Symfony, Laravel, Zend Framework y Yii. El artículo de Younes Rafie, Despliegue Fácil de Aplicaciones PHP con Deployer, es un gran tutorial para desplegar tu aplicación con esta herramienta.
Magallanes es otra herramienta escrita en PHP, con una configuración sencilla con archivos YAML. Soporta múltiples servidores y entornos, despliegue atómico, y tiene algunas tareas integradas que puedes utilizar para herramientas y frameworks comunes.
Gestionar y configurar servidores puede ser una tarea abrumadora cuando se esta trabajando con muchos servidores. Existen herramientas para lidiar con esto, que te permiten automatizar tu infraestructura y asegurarte de que tienes los servidores correctos y que están configurados apropiadamente. A menudo, se integran con los principales proveedores de alojamiento en la nube (Amazon Web Services, Heroku, DigitalOcean, etc.) para gestionar instancias, lo que facilita mucho la escalabilidad de una aplicación.
Ansible es una herramienta que gestiona tu infraestructura a través de archivos YAML. Es fácil para comenzar a usar y puede gestionar aplicaciones complejas y a gran escala. Hay una API para gestionar instancias en la nube y puede administrarlas a través de un inventario dinámico utilizando ciertas herramientas.
Puppet es una herramienta que tiene su propio lenguaje y tipos de archivos para gestionar servidores y configuraciones. Se puede usar en una configuración maestro/cliente o en un modo “sin maestro”. En el modo maestro/cliente, los clientes consultan al maestro(s) central(es) para obtener nuevas configuraciones a intervalos establecidos y se actualizan si es necesario. En el modo sin maestro, puedes enviar cambios a tus nodos.
Chef es un potente marco de integración de sistemas basado en Ruby que puedes utilizar para construir todo tu entorno de servidor o máquinas virtuales. Se integra bien con Amazon Web Services a través de su servicio llamado OpsWorks.
La Integración Continua es una práctica de desarrollo de software en la que los miembros de un equipo integran su trabajo con frecuencia, generalmente cada persona integra al menos una vez al día, lo que conduce a múltiples integraciones por día. Muchos equipos descubren que este enfoque reduce significativamente los problemas de integración y permite desarrollar software cohesivo de manera más rápida.
– Martin Fowler
Existen diferentes maneras de implementar la integración continua para PHP. Travis CI ha hecho un gran trabajo al hacer que la integración continua sea una realidad incluso para proyectos pequeños. Travis CI es un servicio de integración continua hospedado. Se puede integrar con GitHub y ofrece soporte para muchos lenguajes, incluido PHP. GitHub tiene flujos de trabajo de integración continua con GitHub Actions.
Ejecutar tu aplicación en diferentes entornos durante el desarrollo y la producción puede dar lugar a errores extraños cuando la pongas en marcha. También es complicado mantener diferentes entornos de desarrollo actualizados con la misma versión de todas las bibliotecas utilizadas al trabajar con un equipo de desarrolladores.
Si estás desarrollando en Windows y desplegando en Linux (o cualquier sistema que no sea Windows) o si estás desarrollando en equipo, deberías considerar usar una máquina virtual. Esto puede sonar complicado, pero además de los entornos de virtualización ampliamente conocidos como VMware o VirtualBox, hay herramientas adicionales que pueden ayudarte a configurar un entorno virtual en unos pocos pasos sencillos.
Vagrant te ayuda a construir tus máquinas virtuales sobre los entornos virtuales conocidos y configurará estos entornos en base a un único archivo de configuración. Estas máquinas pueden configurarse manualmente, o puedes usar software de “provisión” como Puppet o Chef para hacerlo por ti. Proveer la caja base es una excelente manera de asegurarte de que múltiples máquinas se configuren de manera idéntica y elimina la necesidad de mantener listas de comandos de “configuración” complicadas. También puedes “destruir” tu caja base y recrearla sin muchos pasos manuales, lo que facilita crear una instalación “nueva”.
Vagrant crea carpetas para compartir tu código entre tu máquina host y tu máquina virtual, lo que significa que puedes crear y editar tus archivos en tu máquina host y luego ejecutar el código dentro de tu máquina virtual.
Docker — una alternativa ligera a una máquina virtual completa — se llama así porque se centra en “contenedores”. Un contenedor es un bloque de construcción que, en el caso más simple, realiza una tarea específica, por ejemplo, ejecutar un servidor web. Una “imagen” es el paquete que utilizas para construir el contenedor; Docker tiene un repositorio lleno de ellas.
Una aplicación típica de LAMP podría tener tres contenedores: un servidor web, un proceso de PHP-FPM y MySQL. Al igual que con las carpetas compartidas en Vagrant, puedes dejar tus archivos de aplicación donde están y decirle a Docker dónde encontrarlos.
Puedes generar contenedores desde la línea de comandos (ver ejemplo a continuación) o, para facilitar el mantenimiento, construir un archivo docker-compose.yml
para tu proyecto especificando cuáles crear y cómo se comunican entre sí.
Docker puede ser útil si estás desarrollando múltiples sitios web y deseas la separación que viene de instalar cada uno en su propia máquina virtual, pero no tienes el espacio en disco necesario o el tiempo para mantener todo actualizado. Es eficiente: la instalación y las descargas son más rápidas, solo necesitas almacenar una copia de cada imagen, sin importar cuántas veces se use, los contenedores requieren menos RAM y comparten el mismo núcleo del sistema operativo, por lo que puedes tener más servidores ejecutándose simultáneamente, y lleva solo unos segundos detenerlos y iniciarlos, sin necesidad de esperar a que arranque un servidor completo.
Después de instalar Docker en tu máquina, puedes iniciar un servidor web con un solo comando. Lo siguiente descargará una instalación completamente funcional de Apache con la última versión de PHP, mapear el directorio /path/to/your/php/files
a la raíz del documento, que podrás ver en http://localhost:8080
docker run -d --name my-php-webserver -p 8080:80 -v /path/to/your/php/files:/var/www/html/ php:apache
Esto inicializará y lanzará tu contenedor. -d
hace que se ejecute en segundo plano. Para detenerlo y reiniciarlo, simplemente ejecuta docker stop my-php-webserver
y docker start my-php-webserver
(los otros parámetros no son necesarios nuevamente).
El comando anterior muestra una forma rápida de ejecutar un servidor básico. Hay mucho más que puedes hacer (y miles de imágenes preconstruidas en Docker Hub). Tómate el tiempo para aprender la terminología y leer la Guía del Usuario de Docker para sacarle el máximo provecho, y no ejecutes código aleatorio que hayas descargado sin verificar que sea seguro; las imágenes no oficiales pueden no tener los últimos parches de seguridad. Si tienes dudas, mantente en los repositorios oficiales.
El sitio PHPDocker.io generará automáticamente todos los archivos que necesitas para un stack LAMP/LEMP totalmente funcional, incluyendo tu elección de versión de PHP y extensiones.
PHP es bastante rápido por sí mismo, pero pueden surgir cuellos de botella al hacer conexiones remotas, cargar archivos, etc. Afortunadamente, hay varias herramientas disponibles para acelerar ciertas partes de tu aplicación o reducir la cantidad de veces que estas tareas que consumen tiempo necesitan ejecutarse.
Cuando se ejecuta un archivo PHP, primero debe ser compilado en opcodes (instrucciones en lenguaje de máquina para la CPU). Si el código fuente no ha cambiado, los opcodes serán los mismos, por lo que este paso de compilación se convierte en un desperdicio de recursos de la CPU.
Un caché de opcodes evita la compilación redundante al almacenar los opcodes en la memoria y reutilizarlos en llamadas sucesivas. Normalmente verifica la firma o el tiempo de modificación del archivo primero, en caso de que haya habido algún cambio.
Es probable que un caché de opcodes mejore significativamente la velocidad de tu aplicación. Desde PHP 5.5 hay uno incorporado: Zend OPcache. Dependiendo de tu paquete o distribución de PHP, normalmente está activado por defecto; revisa opcache.enable y la salida de phpinfo()
para asegurarte. Para versiones anteriores, hay una extensión de PECL.
Lee más sobre cachés de opcodes:
A veces puede ser beneficioso almacenar en caché objetos individuales en tu código, como en el caso de datos que son costosos de obtener o llamadas a bases de datos donde el resultado es poco probable que cambie. Puedes usar software de almacenamiento en caché de objetos para mantener estos fragmentos de datos en memoria para un acceso extremadamente rápido más adelante. Si guardas estos elementos en un almacén de datos después de recuperarlos, y luego los obtienes directamente desde la caché para las solicitudes siguientes, puedes obtener una mejora significativa en el rendimiento, así como reducir la carga en tus servidores de bases de datos.
Muchas de las soluciones populares de almacenamiento en caché de bytecode también te permiten almacenar datos personalizados, por lo que hay aún más razones para aprovecharlas. APCu y WinCache proporcionan APIs para guardar datos de tu código PHP en su caché de memoria.
Los sistemas de almacenamiento en caché de objetos en memoria más comúnmente utilizados son APCu y memcached. APCu es una excelente opción para el almacenamiento en caché de objetos, incluye una API simple para agregar tus propios datos a su caché de memoria y es muy fácil de configurar y usar. La única limitación real de APCu es que está vinculado al servidor donde está instalado. Memcached, por otro lado, se instala como un servicio separado y se puede acceder a él a través de la red, lo que significa que puedes almacenar objetos en un almacén de datos de alta velocidad en una ubicación central y muchos sistemas diferentes pueden obtenerlos desde allí.
Ten en cuenta que si la caché se comparte o no entre procesos PHP depende de cómo se utilice PHP. Al ejecutar PHP a través de PHP-FPM, la caché se comparte entre todos los procesos de todos los pools. Al ejecutar PHP como una aplicación (Fast-)CGI dentro de tu servidor web, la caché no se comparte, es decir, cada proceso PHP tendrá sus propios datos APCu. Al ejecutar PHP desde la línea de comandos, la caché no se comparte y solo existirá durante la duración del comando. Por lo tanto, debes ser consciente de tu situación y objetivos. Además, podrías considerar usar memcached en su lugar, ya que no está vinculado a los procesos PHP.
En una configuración en red, APCu generalmente superará a memcached en términos de velocidad de acceso, pero memcached podrá escalar más rápido y en mayor medida. Si no esperas tener varios servidores ejecutando tu aplicación, o no necesitas las características adicionales que ofrece memcached, entonces probablemente APCu sea tu mejor opción para el almacenamiento en caché de objetos.
Ejemplo de lógica usando APCu:
<?php
// check if there is data saved as 'expensive_data' in cache
$data = apcu_fetch('expensive_data');
if ($data === false) {
// data is not in cache; save result of expensive call for later use
apcu_add('expensive_data', $data = get_expensive_data());
}
print_r($data);
Ten en cuenta que antes de PHP 5.5, existía la extensión APC, que proporcionaba tanto una caché de objetos como una caché de bytecode. El nuevo APCu es un proyecto para llevar la caché de objetos de APC a PHP 5.5+, ya que PHP ahora tiene una caché de bytecode incorporada (OPcache).
PHPDoc es un estándar informal para comentar el código PHP. Hay muchas [etiquetas] diferentes disponibles. La lista completa de etiquetas y ejemplos se puede encontrar en el [manual de PHPDoc].
A continuación se muestra un ejemplo de cómo podrías documentar una clase con algunos métodos:
<?php
/**
* @author A Name <a.name@example.com>
* @link https://www.phpdoc.org/docs/latest/index.html
*/
class DateTimeHelper
{
/**
* @param mixed $anything Anything that we can convert to a \DateTime object
*
* @throws \InvalidArgumentException
*
* @return \DateTime
*/
public function dateTimeFromAnything($anything)
{
$type = gettype($anything);
switch ($type) {
// Some code that tries to return a \DateTime object
}
throw new \InvalidArgumentException(
"Failed Converting param of type '{$type}' to DateTime object"
);
}
/**
* @param mixed $date Anything that we can convert to a \DateTime object
*
* @return void
*/
public function printISO8601Date($date)
{
echo $this->dateTimeFromAnything($date)->format('c');
}
/**
* @param mixed $date Anything that we can convert to a \DateTime object
*/
public function printRFC2822Date($date)
{
echo $this->dateTimeFromAnything($date)->format('r');
}
}
La documentación de la clase en su conjunto tiene la etiqueta @author y una etiqueta @link. La etiqueta @author se usa para documentar al autor del código y puede repetirse para documentar a varios autores. La etiqueta @link se usa para enlazar a un sitio web que indique una relación entre el sitio web y el código.
Dentro de la clase, el primer método tiene una etiqueta @param que documenta el tipo, nombre y descripción del parámetro que se pasa al método. Además, tiene las etiquetas @return y @throws para documentar el tipo de retorno y cualquier excepción que pueda lanzarse, respectivamente.
Los métodos segundo y tercero son muy similares y tienen una única etiqueta @param, al igual que el primer método. La diferencia importante entre los bloques de documentación de los métodos segundo y tercero es la inclusión/exclusión de la etiqueta @return. @return void
nos informa explícitamente que no hay retorno; históricamente, omitir la declaración @return void
también resulta en la misma acción (sin retorno).
Es difícil encontrar miembros de la comunidad PHP interesantes y bien informados cuando se está empezando. Puedes encontrar una lista abreviada de miembros de la comunidad PHP para empezar en:
En lugar de reinventar la rueda, muchos desarrolladores de PHP utilizan frameworks para crear aplicaciones web. Los frameworks eliminan muchas de las preocupaciones de bajo nivel y proporcionan interfaces útiles y fáciles de usar para completar tareas comunes.
No es necesario utilizar un framework para todos los proyectos. A veces lo mejor es utilizar PHP sin más, pero si necesitas un framework, existen tres tipos principales:
Los micro-frameworks son esencialmente una envoltura para enrutar una petición HTTP a un callback, controlador, método, etc. tan rápido como sea posible, y a veces vienen con algunas bibliotecas adicionales para ayudar al desarrollo, tales como envolturas básicas de bases de datos y similares. Se utilizan principalmente para crear servicios HTTP remotos.
Muchos frameworks añaden un número considerable de funciones además de las disponibles en un microframework; son los llamados Full-Stack Frameworks. Suelen incluir ORM, paquetes de autenticación, etc.
Los frameworks basados en componentes son colecciones de bibliotecas especializadas y de propósito único. Los distintos frameworks basados en componentes pueden utilizarse juntos para crear un microframe o un framework completo.
Como ya se ha mencionado, los “componentes” son otro enfoque del objetivo común de crear, distribuir e implementar código compartido. Existen varios repositorios de componentes, los dos principales de los cuales son:
Ambos repositorios tienen herramientas de línea de comandos asociadas para ayudar en los procesos de instalación y actualización, y se han explicado con más detalle en la sección Gestión de dependencias.
También existen frameworks basados en componentes y proveedores de componentes que no ofrecen ningún tipo de framework. Estos proyectos proporcionan otra fuente de paquetes que idealmente tienen poca o ninguna dependencia de otros paquetes, o frameworks específicos.
Por ejemplo, puede utilizar el Paquete de Validación FuelPHP, sin necesidad de utilizar el propio framework FuelPHP.
Los componentes Illuminate de Laravel se desacoplarán mejor del framework Laravel. Por ahora, sólo los componentes mejor desacoplados del framework Laravel se enumeran más arriba..
Puede suscribirse a boletines semanales para mantenerse informado sobre nuevas bibliotecas, últimas noticias, eventos y anuncios generales, así como sobre los recursos adicionales que se publican de vez en cuando:
También hay semanarios en otras plataformas que podrían interesarte; aquí tienes una lista de algunos.
Existen muchos libros sobre PHP; lamentablemente, algunos son ya bastante antiguos y han dejado de ser precisos. En particular, evite libros sobre “PHP 6”, una versión que ahora nunca existirá. La siguiente versión mayor de PHP después de la 5.6 fue “PHP 7”, en parte debido a esto.
Esta sección pretende ser un documento vivo de libros recomendados sobre desarrollo PHP en general. Si desea que su libro sea añadido, envíe un PR y será revisado para comprobar su relevancia.
La comunidad de PHP es tan diversa como grande y sus miembros están listos y dispuestos a apoyar a los nuevos programadores de PHP. Considera unirte a tu grupo de usuarios local de PHP (PUG) o asistir a conferencias más grandes de PHP para aprender más sobre las mejores prácticas mostradas aquí. Puedes interactuar en IRC en el canal #phpc en irc.freenode.com y seguir el perfil @phpc en Twitter o Mastodon. Sal y conoce nuevos desarrolladores, aprende nuevos temas y, sobre todo, haz nuevos amigos! Otros recursos de la comunidad incluyen StackOverflow.
Si vives en una ciudad grande, es probable que haya un grupo de usuarios de PHP cerca. Puedes encontrar fácilmente tu PUG local en PHP.ug. Fuentes alternativas podrían ser Meetup.com o realizar una búsqueda de php user group near me usando tu motor de búsqueda favorito (por ejemplo: Google). Si vives en una ciudad más pequeña, puede que no haya un PUG local; si ese es el caso, ¡créalo tú mismo!
Se debe hacer una mención especial de dos grupos de usuarios globales: NomadPHP y PHPWomen. NomadPHP ofrece reuniones en línea del grupo de usuarios dos veces al mes, con presentaciones de algunos de los mejores ponentes de la comunidad PHP. PHPWomen es un grupo de usuarios no exclusivo, originalmente dirigido a mujeres en el mundo PHP. La membresía está abierta a todas las personas que apoyen una comunidad más diversa. PHPWomen proporciona una red de apoyo, mentoría y educación, y promueve generalmente la creación de un ambiente “amigable para las mujeres” y profesional.
La comunidad de PHP también organiza conferencias regionales y nacionales más grandes en muchos países alrededor del mundo. Los miembros más conocidos de la comunidad PHP suelen hablar en estos eventos más grandes, por lo que es una gran oportunidad para aprender directamente de los líderes de la industria.
ElePHPant es esa hermosa mascota del proyecto PHP con un elefante en su diseño. Fue originalmente creada para el proyecto PHP en 1998 por Vincent Pontier - el padre espiritual de miles de elePHPants alrededor del mundo - y diez años después también nacieron adorables peluches de elefante. Ahora los elePHPants están presentes en muchas conferencias de PHP y con muchos desarrolladores de PHP en sus computadoras, brindando diversión e inspiración.