Benvido

Hai moita información desactualizada na Web que leva aos novos usuarios de PHP por mal camiño, propagando malas prácticas e código inseguro. PHP: The Right Way é unha referencia fácil de ler e rápida para os estándares de codificación populares de PHP, enlaces a tutoriais autorizados pola Web, e o que os colaboradores consideran as mellores prácticas na actualidade.

Non hai unha forma canónica de usar PHP. Este sitio web pretende introducir aos novos desenvolvedores de PHP nalgúns temas que poden non descubrir ata que sexa demasiado tarde, e pretende dar aos profesionais experimentados algunhas ideas frescas sobre aqueles temas que levan anos facendo sen reconsiderar nunca. Este sitio web tampouco che dirá que ferramentas usar, senón que ofrecerá suxestións para múltiples opcións, cando sexa posible explicando as diferenzas no enfoque e caso de uso.

Este é un documento vivo e continuará sendo actualizado con máis información útil e exemplos conforme estean dispoñibles.

Traducións

PHP: The Right Way está traducido a moitos idiomas diferentes:

Libro

A versión máis recente de PHP: The Right Way tamén está dispoñible en formatos PDF, EPUB e MOBI. Ir a Leanpub

Como Contribuír

Axuda a facer deste sitio web o mellor recurso para os novos programadores de PHP! Contribuír en GitHub

Back to Top

Comezando

Usa a Versión Estable Actual (8.5)

Se estás a comezar con PHP, comeza coa versión estable actual de PHP 8.5. PHP 8.x engade moitas novas funcionalidades respecto as versións máis antigas 7.x e 5.x. O motor foi reescrito en gran parte, e PHP agora é incluso máis rápido que as versións antigas. PHP 8 é unha actualización maior da linguaxe e contén moitas novas funcionalidades e optimizacións.

Deberías tentar actualizar á versión estable máis recente rapidamente - PHP 7.4 xa está no Fin da Vida. A actualización é fácil, xa que non hai moitas roturas de compatibilidade cara atrás PHP 8.0, PHP 8.1, PHP 8.2, PHP 8.3, PHP 8.4, PHP 8.5. Se non estás seguro de en que versión está unha función ou funcionalidade, podes consultar a documentación de PHP no sitio web php.net.

Servidor web integrado

Con PHP 5.4 ou máis recente, podes comezar a aprender PHP sen instalar e configurar un servidor web completo. Para iniciar o servidor, executa o seguinte comando desde a túa terminal na raíz web do teu proxecto:

> php -S localhost:8000

Configuración de macOS

macOS 12 (Monterey) e versións posteriores non veñen con PHP preinstalado. As versións anteriores de macOS inclúen PHP pero están atrasadas respecto á versión estable máis recente. Hai múltiples formas de instalar a versión máis recente de PHP en macOS.

Instalar PHP via Homebrew

Homebrew é un xestor de paquetes para macOS que che axuda a instalar PHP e varias extensións facilmente. O repositorio principal de Homebrew proporciona “fórmulas” para PHP 8.1, 8.2, 8.3, 8.4 and 8.5. Instala a versión máis recente con este comando:

brew install php

Podes cambiar entre versións de PHP de Homebrew modificando a túa variable PATH. Alternativamente, podes usar brew-php-switcher para cambiar versións de PHP automaticamente.

Tamén podes cambiar entre versións de PHP manualmente desvinculando e vinculando a versión desexada:

brew unlink php
brew link --overwrite php@8.2
brew unlink php
brew link --overwrite php@8.3

Instalar PHP via Macports

O Proxecto MacPorts é unha iniciativa da comunidade de código aberto para deseñar un sistema fácil de usar para compilar, instalar e actualizar software de código aberto baseado en liña de comandos, X11 ou Aqua no sistema operativo macOS.

MacPorts soporta binarios precompilados, polo que non necesitas recompilar cada dependencia desde os arquivos tar.gz de código fonte, salva a túa vida se non tes ningún paquete instalado no teu sistema.

Neste punto, podes instalar php54, php55, php56, php70, php71, php72, php73, php74, php80, php81, php82, php83 ou php84 usando o comando port install, por exemplo:

sudo port install php74
sudo port install php83

E podes executar o comando select para cambiar o teu PHP activo:

sudo port select --set php php83

Instalar PHP via phpbrew

phpbrew é unha ferramenta para instalar e xestionar múltiples versións de PHP. Isto pode ser realmente útil se dúas aplicacións/proxectos diferentes requiren diferentes versións de PHP, e non estás usando máquinas virtuais.

Instalar PHP via o instalador binario de Liip

Outra opción popular é php-osx.liip.ch que proporciona métodos de instalación dunha liña para versións 5.3 ata 7.3. Non sobrescribe os binarios de PHP instalados por Apple, senón que instala todo nunha localización separada (/usr/local/php5).

Compilar desde o Código Fonte

Outra opción que che dá control sobre a versión de PHP que instalas, é compilalo ti mesmo. Nese caso asegúrate de ter instalado Xcode ou o substituto de Apple “Command Line Tools for XCode” descargable desde o Centro de Desenvolvedores de Apple.

Instaladores Todo-en-Un

As solucións listadas arriba principalmente manexan PHP en si, e non proporcionan cousas como Apache, Nginx ou un servidor SQL. As solucións “todo-en-un” como MAMP e XAMPP instalarán estes outros bits de software para ti e os conectarán todos xuntos, pero a facilidade de configuración vén cun trade-off de flexibilidade.

Configuración de Windows

Podes descargar os binarios desde windows.php.net/download. Despois da extracción de PHP, recoméndase configurar o PATH á raíz da túa carpeta PHP (onde está localizado php.exe) para que poidas executar PHP desde calquera lugar.

Para aprender e desenvolvemento local, podes usar o servidor web integrado con PHP 5.4+ polo que non necesitas preocuparte por configuralo. Se queres un “todo-en-un” que inclúa un servidor web completo e MySQL tamén, entón ferramentas como XAMPP, EasyPHP, OpenServer e WAMP axudarán a conseguir un entorno de desenvolvemento de Windows funcionando rapidamente. Dito isto, estas ferramentas serán un pouco diferentes do entorno de produción, polo que ten coidado coas diferenzas de ambiente se estás a traballar en Windows e desplegando en Linux.

Se necesitas executar o teu sistema de produción en Windows, entón IIS7 che dará a mellor estabilidade e rendemento. Podes usar phpmanager (un plugin GUI para IIS7) para facer a configuración e xestión de PHP simple. IIS7 ven con FastCGI integrado e listo para usar, só necesitas configurar PHP como un manexador. Para soporte e recursos adicionais hai unha área dedicada en iis.net para PHP.

Xeralmente executar a túa aplicación en diferentes ambientes en desenvolvemento e produción pode levar a estraños bugs aparecendo cando vas en vivo. Se estás a desenvolver en Windows e desplegando en Linux (ou calquera cousa non-Windows) entón deberías considerar usar unha Máquina Virtual.

Chris Tankersley ten unha entrada de blog moi útil sobre que ferramentas usa para desenvolvemento PHP usando Windows.

Configuración de Linux

A maioría das distribucións GNU/Linux veñen con PHP dispoñible desde os repositorios oficiais, pero eses paquetes xeralmente están un pouco atrasados respecto á versión estable actual. Hai múltiples formas de obter versións máis recentes de PHP en tales distribucións.

Distribucións baseadas en Ubuntu

En Ubuntu e distribucións GNU/Linux baseadas en Debian, por exemplo, as mellores alternativas para paquetes nativos son proporcionadas e mantidas por Ondřej Surý, a través do seu Personal Package Archive (PPA) en Ubuntu e DPA/bikeshed en Debian. Atopa instrucións para cada un destes abaixo.

Para distribucións Ubuntu, o PPA de Ondřej Surý proporciona versións soportadas de PHP xunto con moitas extensións PECL. Para engadir este PPA ao teu sistema, executa os seguintes pasos na túa terminal:

  1. Primeiro, engade o PPA ás fontes de software do teu sistema usando o comando:

    sudo add-apt-repository ppa:ondrej/php
    
  2. Despois de engadir o PPA, actualiza a lista de paquetes do teu sistema:

    sudo apt update
    

Isto asegurará que o teu sistema poida acceder e instalar os paquetes PHP máis recentes dispoñibles no PPA.

Distribucións baseadas en Debian

Para distribucións baseadas en Debian, Ondřej Surý tamén proporciona un bikeshed (equivalente de Debian dun PPA). Para engadir o bikeshed ao teu sistema e actualizalo, segue estes pasos:

  1. Asegúrate de que tes acceso root. Se non, poderías necesitar usar sudo para os seguintes comandos.

  2. Actualiza a lista de paquetes do teu sistema:

    sudo apt-get update
    
  3. Instala lsb-release, ca-certificates, e curl:

    sudo apt-get -y install lsb-release ca-certificates curl
    
  4. Descarga a chave de sinatura para o repositorio:

    sudo curl -sSLo /usr/share/keyrings/deb.sury.org-php.gpg https://packages.sury.org/php/apt.gpg
    
  5. Engade o repositorio ás fontes de software do teu 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'
    
  6. Finalmente, actualiza a lista de paquetes do teu sistema de novo:

    sudo apt-get update
    

Con estes pasos, o teu sistema poderá instalar os paquetes PHP máis recentes desde o bikeshed.

Distribucións baseadas en RPM

En distribucións baseadas en RPM (CentOS, Fedora, RHEL, etc.) podes usar o repositorio RPM de Remi para instalar a versión máis recente de PHP ou para ter múltiples versións de PHP dispoñibles simultaneamente.

Hai un asistente de configuración dispoñible para configurar a túa distribución baseada en RPM.

Todo isto dito, sempre podes usar contedores ou compilar o código fonte de PHP desde cero.

Estrutura de directorios común

Unha pregunta común entre aqueles que comezan a escribir programas para a web é, “onde poño as miñas cousas?” Ao longo dos anos, esta resposta foi consistentemente “onde está o DocumentRoot.” Aínda que esta resposta non é completa, é un gran lugar para comezar.

Por razóns de seguridade, os arquivos de configuración non deberían ser accesibles polos visitantes dun sitio; polo tanto, os scripts públicos mantéñense nun directorio público e as configuracións e datos privados mantéñense fóra dese directorio.

Para cada equipo, CMS, ou framework no que se traballa, cada unha desas entidades usa unha estrutura de directorios estándar. Con todo, se un está a comezar un proxecto só, saber que estrutura de sistema de arquivos usar pode ser desalentador.

Paul M. Jones fixo algunha investigación fantástica sobre prácticas comúns de decenas de miles de proxectos de github no ámbito de PHP. Compilou unha estrutura estándar de arquivos e directorios, o Standard PHP Package Skeleton, baseado nesta investigación. Nesta estrutura de directorios, DocumentRoot debería apuntar a public/, as probas unitarias deberían estar no directorio tests/, e as librarías de terceiros, como as instaladas por composer, pertencen ao directorio vendor/. Para outros arquivos e directorios, seguir o Standard PHP Package Skeleton terá máis sentido para os colaboradores dun proxecto.

Back to Top

Guía de estilo de código

A comunidade PHP é grande e diversa, composta por innumerables librarías, frameworks e compoñentes. É común que os desenvolvedores de PHP elixan varios destes e os combinen nun único proxecto. É importante que o código PHP adhira (o máis próximo posible) a un estilo de código común para facilitar aos desenvolvedores mesturar e combinar varias librarías para os seus proxectos.

O Framework Interop Group propuxo e aprobou unha serie de recomendacións de estilo. Non todas elas están relacionadas co estilo de código, pero as que o están son PSR-1, PSR-12, PSR-4 e PER Coding Style. Estas recomendacións son meramente un conxunto de regras que moitos proxectos como Drupal, Zend, Symfony, Laravel, CakePHP, phpBB, AWS SDK, FuelPHP, Lithium, etc. están adoptando. Podes usalas para os teus propios proxectos, ou continuar usando o teu propio estilo persoal.

Idealmente, deberías escribir código PHP que adhira a un estándar coñecido. Isto podería ser calquera combinación de PSRs, ou un dos estándares de codificación feitos por PEAR ou Zend. Isto significa que outros desenvolvedores poden ler e traballar facilmente co teu código, e as aplicacións que implementan os compoñentes poden ter consistencia mesmo cando traballan con moito código de terceiros.

Podes usar PHP_CodeSniffer para verificar o código contra calquera unha destas recomendacións, e plugins para editores de texto como Sublime Text para recibir retroalimentación en tempo real.

Podes arranxar o layout do código automaticamente usando unha das seguintes ferramentas:

E podes executar phpcs manualmente desde o shell:

phpcs -sw --standard=PSR1 file.php

Mostrará erros e describirá como arranxalos. Tamén pode ser útil incluír o comando phpcs nun hook pre-commit de git co argumento CLI --filter=GitStaged. Dese xeito, o código que contén violacións contra o estándar elixido non pode entrar no repositorio ata que esas violacións foron arranxadas.

Se tes PHP_CodeSniffer, entón podes arranxar os problemas de layout do código reportados por el, automaticamente, co PHP Code Beautifier and Fixer.

phpcbf -w --standard=PSR1 file.php

Outra opción é usar o PHP Coding Standards Fixer. Mostrará que tipo de erros tiña a estrutura do código antes de arranxalos.

php-cs-fixer fix -v --rules=@PSR1 file.php

O inglés é preferido para todos os nomes de símbolos e infraestrutura de código. Os comentarios poden ser escritos en calquera idioma facilmente lexible por todas as partes actuais e futuras que poden estar a traballar na base de código.

Finalmente, un bo recurso complementario para escribir código PHP limpo é Clean Code PHP.

Back to Top

Destacados da Linguaxe

Paradigmas de Programación

PHP é unha linguaxe flexible e dinámica que soporta unha variedade de técnicas de programación. Evolucionou dramaticamente ao longo dos anos, notablemente engadindo un modelo sólido orientado a obxectos en PHP 5.0 (2004), funcións anónimas e espazos de nomes en PHP 5.3 (2009), e traits en PHP 5.4 (2012).

Programación Orientada a Obxectos

PHP ten un conxunto moi completo de funcionalidades de programación orientada a obxectos incluíndo soporte para clases, clases abstractas, interfaces, herdanza, construtores, clonación, excepcións, e máis.

Programación Funcional

PHP soporta funcións de primeira clase, significando que unha función pode ser asignada a unha variable. Tanto funcións definidas polo usuario como funcións integradas poden ser referenciadas por unha variable e invocadas dinamicamente. As funcións poden ser pasadas como argumentos a outras funcións (unha funcionalidade chamada Funcións de Orde Superior) e as funcións poden retornar outras funcións.

A recursión, unha funcionalidade que permite a unha función chamarse a si mesma, está soportada pola linguaxe, pero a maioría do código PHP está enfocado na iteración.

As novas funcións anónimas (con soporte para closures) están presentes desde PHP 5.3 (2009).

PHP 5.4 engadiu a capacidade de vincular closures ao ámbito dun obxecto e tamén mellorou o soporte para callables de tal xeito que poden ser usados intercambiablemente con funcións anónimas en case todos os casos.

Meta Programación

PHP soporta varias formas de meta-programación a través de mecanismos como a API de Reflection e Métodos Máxicos. Hai moitos Métodos Máxicos dispoñibles como __get(), __set(), __clone(), __toString(), __invoke(), etc. que permiten aos desenvolvedores enganchar no comportamento das clases. Os desenvolvedores de Ruby a miúdo din que a PHP lle falta method_missing, pero está dispoñible como __call() e __callStatic().

Espazos de Nomes

Como se mencionou arriba, a comunidade PHP ten moitos desenvolvedores creando moito código. Isto significa que o código PHP dunha libraría podería usar o mesmo nome de clase que outra. Cando ambas as librarías son usadas no mesmo espazo de nomes, coliden e causan problemas.

Os espazos de nomes solucionan este problema. Como se describe no manual de referencia de PHP, os espazos de nomes poden ser comparados a directorios do sistema operativo que espacian os arquivos; dous arquivos co mesmo nome poden coexistir en directorios separados. Do mesmo xeito, dúas clases PHP co mesmo nome poden coexistir en espazos de nomes PHP separados. É tan simple como iso.

É importante para ti espaziar o teu código para que poida ser usado por outros desenvolvedores sen medo de colidir con outras librarías.

Unha forma recomendada de usar espazos de nomes está esbozada en PSR-4, que pretende proporcionar un estándar de arquivo, clase e convención de espazo de nomes para permitir código plug-and-play.

En outubro de 2014 o PHP-FIG deprecou o estándar anterior de autoloading: PSR-0. Tanto PSR-0 como PSR-4 son aínda perfectamente usables. O último require PHP 5.3, polo que moitos proxectos só PHP 5.2 implementan PSR-0.

Se vas usar un estándar de autoloader para unha nova aplicación ou paquete, mira PSR-4.

Libraría Estándar de PHP

A libraría Estándar de PHP (SPL) está empaquetada con PHP e proporciona unha colección de clases e interfaces. Está feita principalmente de clases de estruturas de datos comúns necesarias (pila, cola, montón, e así por diante), e iteradores que poden atravesar sobre estas estruturas de datos ou as túas propias clases que implementan interfaces SPL.

Interfaz de Liña de Comandos

PHP foi creado para escribir aplicacións web, pero tamén é útil para programar scripts de interfaz de liña de comandos (CLI). Os programas PHP de liña de comandos poden axudar a automatizar tarefas comúns como probas, despliegue e administración de aplicacións.

Os programas CLI PHP son poderosos porque podes usar o código da túa aplicación directamente sen ter que crear e asegurar unha GUI web para iso. Só asegúrate de non poñer os teus scripts PHP CLI no teu directorio raíz web público!

Tenta executar PHP desde a túa liña de comandos:

> php -i

A opción -i imprimirá a túa configuración PHP xusto como a función phpinfo().

A opción -a proporciona un shell interactivo, similar ao IRB de ruby ou o shell interactivo de python. Hai un número de outras opcións de liña de comandos útiles tamén.

Escribamos un programa CLI simple “Ola, $name”. Para probalo, crea un arquivo chamado hello.php, como abaixo.

<?php
if ($argc !== 2) {
    echo "Usage: php hello.php <name>" . PHP_EOL;
    exit(1);
}
$name = $argv[1];
echo "Hello, $name" . PHP_EOL;

PHP configura dúas variables especiais baseadas nos argumentos co que o teu script é executado. $argc é unha variable enteira que contén a conta de argumentos e $argv é unha variable array que contén o valor de cada argumento. O primeiro argumento é sempre o nome do teu arquivo script PHP, neste caso hello.php.

A expresión exit() é usada cun número non cero para deixar que o shell saiba que o comando fallou. Códigos de saída comúns poden ser atopados aquí.

Para executar o noso script, de arriba, desde a liña de comandos:

> php hello.php
Usage: php hello.php <name>
> php hello.php world
Hello, world

Xdebug

Unha das ferramentas máis útiles no desenvolvemento de software é un depurador adecuado. Permíche rastrexar a execución do teu código e monitorizar o contido da pila. Xdebug, o depurador de PHP, pode ser utilizado por varios IDEs para proporcionar puntos de interrupción e inspección da pila. Tamén pode permitir que ferramentas como PHPUnit e KCacheGrind realicen análise de cobertura de código e perfilado de código.

Se te atopas nun apuro, disposto a recurrir a var_dump()/print_r(), e aínda non podes atopar a solución - quizais necesites usar o depurador.

Instalar Xdebug pode ser complicado, pero unha das súas funcionalidades máis importantes é “Depuración Remota” - se desenvolves código localmente e entón o probas dentro dunha VM ou noutro servidor, a Depuración Remota é a funcionalidade que querrás habilitar inmediatamente.

Tradicionalmente, modificarás o teu Apache VHost ou arquivo .htaccess con estes valores:

php_value xdebug.remote_host 192.168.?.?
php_value xdebug.remote_port 9000

O “host remoto” e “porto remoto” corresponderán ao teu computador local e o porto que configures o teu IDE para escoitar. Entón é só unha cuestión de poñer o teu IDE en modo “escoitar conexións”, e cargar a URL:

http://your-website.example.com/index.php?XDEBUG_SESSION_START=1

O teu IDE agora interceptará o estado actual mentres o script executa, permitíndoche establecer puntos de interrupción e sondar os valores en memoria.

Os depuradores gráficos fan moi fácil percorrer o código paso a paso, inspeccionar variables, e avaliar código contra o runtime en vivo. Moitos IDEs teñen soporte integrado ou baseado en plugins para depuración gráfica con Xdebug. MacGDBp é un GUI de Xdebug gratuito, de código aberto, independente para macOS.

Back to Top

Xestión de Dependencias

Hai unha tonelada de librarías, frameworks e compoñentes PHP para elixir. O teu proxecto probablemente usará varios deles — estas son as dependencias do proxecto. PHP non tiña unha boa forma de xestionar estas dependencias do proxecto. Mesmo se as xestionabas manualmente, aínda tiñas que preocuparte polos autoloaders. Iso xa non é un problema.

Actualmente hai dous sistemas principais de xestión de paquetes para PHP - Composer e PEAR. Composer é actualmente o xestor de paquetes máis popular para PHP, con todo durante moito tempo PEAR foi o xestor de paquetes principal en uso. Coñecer a historia de PEAR é unha boa idea, xa que aínda podes atopar referencias a el mesmo se nunca o usas.

Composer e Packagist

Composer é o xestor de dependencias recomendado para PHP. Lista as dependencias do teu proxecto nun arquivo composer.json e, con uns poucos comandos simples, Composer descargará automaticamente as dependencias do teu proxecto e configurará o autoloading para ti. Composer é análogo a NPM no mundo de node.js, ou Bundler no mundo de Ruby.

Hai unha plethora de librarías PHP que son compatibles con Composer e listas para ser usadas no teu proxecto. Estes “paquetes” están listados en Packagist, o repositorio oficial para librarías PHP compatibles con Composer.

Como Instalar Composer

A forma máis segura de descargar composer é seguindo as instrucións oficiais. Isto verificará que o instalador non está corrompido ou manipulado. O instalador instala un binario composer.phar no teu directorio de traballo actual.

Recomendamos instalar Composer globalmente (ex. unha única copia en /usr/local/bin). Para facelo, executa este comando a continuación:

mv composer.phar /usr/local/bin/composer

Nota: Se o anterior falla debido a permisos, prefixa con sudo.

Para executar un Composer instalado localmente usarías php composer.phar, globalmente é simplemente composer.

Instalando en Windows

Para usuarios de Windows a forma máis fácil de comezar é usar o instalador ComposerSetup, que realiza unha instalación global e configura o teu $PATH para que poidas simplemente chamar composer desde calquera directorio na túa liña de comandos.

Como Definir e Instalar Dependencias

Composer mantén un rexistro das dependencias do teu proxecto nun arquivo chamado composer.json. Podes xestionalo manualmente se queres, ou usar o propio Composer. O comando composer require engade unha dependencia do proxecto e se non tes un arquivo composer.json, un será creado. Aquí hai un exemplo que engade Twig como unha dependencia do teu proxecto.

composer require twig/twig:^2.0

Alternativamente, o comando composer init guiaráche a través da creación dun arquivo composer.json completo para o teu proxecto. De calquera forma, unha vez que creaches o teu arquivo composer.json podes dicirlle a Composer que descargue e instale as túas dependencias no directorio vendor/. Isto tamén se aplica a proxectos que descargaches que xa proporcionan un arquivo composer.json:

composer install

A continuación, engade esta liña ao arquivo PHP principal da túa aplicación; isto lle dirá a PHP que use o autoloader de Composer para as dependencias do teu proxecto.

<?php
require 'vendor/autoload.php';

Agora podes usar as dependencias do teu proxecto, e serán autoloaded a demanda.

Actualizando as túas dependencias

Composer crea un arquivo chamado composer.lock que almacena a versión exacta de cada paquete que descargou cando executaste por primeira vez composer install. Se compartes o teu proxecto con outros, asegúrate de que o arquivo composer.lock está incluído, para que cando eles executem composer install obteñan as mesmas versións que ti. Para actualizar as túas dependencias, executa composer update. Non uses composer update cando desplegues, só composer install, doutra forma poderías acabar con diferentes versións de paquetes en produción.

Isto é máis útil cando defines os teus requisitos de versión de forma flexible. Por exemplo, un requisito de versión de ~1.8 significa “calquera cousa máis nova que 1.8.0, pero menos que 2.0.x-dev”. Tamén podes usar o comodín * como en 1.8.*. Agora o comando composer update de Composer actualizará todas as túas dependencias á versión máis nova que se axuste ás restriccións que defines.

Notificacións de Actualización

Para recibir notificacións sobre novas versións podes rexistrarte en libraries.io, un servizo web que pode monitorizar dependencias e enviarche alertas sobre actualizacións.

Verificando as túas dependencias para problemas de seguridade

O Local PHP Security Checker é unha ferramenta de liña de comandos, que examinará o teu arquivo composer.lock e che dirá se necesitas actualizar algunha das túas dependencias.

Manejando dependencias globais con Composer

Composer tamén pode manexar dependencias globais e os seus binarios. O uso é directo, todo o que necesitas facer é prefixar o teu comando con global. Se por exemplo quixeras instalar PHPUnit e telo dispoñible globalmente, executarías o seguinte comando:

composer global require phpunit/phpunit

Isto creará unha carpeta ~/.composer onde residen as túas dependencias globais. Para ter os binarios dos paquetes instalados dispoñibles en todas partes, entón engadirías a carpeta ~/.composer/vendor/bin á túa variable $PATH.

PEAR

Un xestor de paquetes veterano que algúns desenvolvedores PHP disfrutan é PEAR. Comportase de forma similar a Composer, pero ten algunhas diferenzas notábeis.

PEAR require que cada paquete teña unha estrutura específica, o que significa que o autor do paquete debe preparalo para uso con PEAR. Usar un proxecto que non foi preparado para traballar con PEAR non é posible.

PEAR instala paquetes globalmente, o que significa que despois de instalalos unha vez están dispoñibles para todos os proxectos nese servidor. Isto pode ser bo se moitos proxectos dependen do mesmo paquete coa mesma versión pero pode levar a problemas se surxen conflitos de versión entre dous proxectos.

Como instalar PEAR

Podes instalar PEAR descargando o instalador .phar e executándoo. A documentación de PEAR ten instrucións de instalación detalladas para cada sistema operativo.

Se estás usando Linux, tamén podes mirar o teu xestor de paquetes de distribución. Debian e Ubuntu, por exemplo, teñen un paquete apt php-pear.

Como instalar un paquete

Se o paquete está listado na lista de paquetes PEAR, podes instalalo especificando o nome oficial:

pear install foo

Se o paquete está hospedado noutro canal, necesitas descubrir o canal primeiro e tamén especificalo cando instales. Vexa a documentación de uso de canais para máis información sobre este tema.

Manejando dependencias PEAR con Composer

Se xa estás usando Composer e quixeras instalar algún código PEAR tamén, podes usar Composer para manexar as túas dependencias PEAR. Os repositorios PEAR xa non son directamente soportados por Composer versión 2, polo que debes engadir 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/"}
    }
}

A primeira sección "repositories" será usada para deixar que Composer saiba que debería “inicializar” (ou “descubrir” en terminoloxía PEAR) o repo pear. Entón a sección require prefixará o nome do paquete así:

pear-channel/package

O prefixo “pear” está codificado a man para evitar calquera conflito, xa que un canal pear podería ser o mesmo que outro nome de vendor de paquetes por exemplo, entón o nome curto do canal (ou URL completa) pode ser usado para referenciar en que canal está o paquete.

Cando este código é instalado estará dispoñíbel no teu directorio vendor e automaticamente dispoñíbel a través do autoloader de Composer:

vendor/pear2/pear2-http-request/pear2/HTTP/Request.php

Para usar este paquete PEAR simplemente referénciao así:

<?php
require __DIR__ . '/vendor/autoload.php';

use PEAR2\HTTP\Request;

$request = new Request();

Back to Top

Prácticas de Codificación

Os Básicos

PHP é unha linguaxe vasta que permite aos codificadores de todos os niveis a capacidade de producir código non só rapidamente, senón eficientemente. Con todo, mentres avanzamos a través da linguaxe, a miúdo esquecemos os básicos que primeiro aprendemos (ou pasamos por alto) en favor de atallos e/ou malos hábitos. Para axudar a combater este problema común, esta sección pretende recordar aos codificadores as prácticas básicas de codificación dentro de PHP.

Data e Hora

PHP ten unha clase chamada DateTime para axudarte cando leas, escribas, compares ou calcules con data e hora. Hai moitas funcións relacionadas con data e hora en PHP ademais de DateTime, pero proporciona unha interface orientada a obxectos agradable para os usos máis comúns. DateTime pode manexar zonas horarias, pero iso está fóra do alcance desta breve introdución.

Para comezar a traballar con DateTime, converte a cadea bruta de data e hora a un obxecto co método factory createFromFormat() ou fai new DateTime para obter a data e hora actual. Usa o método format() para converter DateTime de volta a unha cadea para saída.

<?php
$raw = '22. 11. 1968';
$start = DateTime::createFromFormat('d. m. Y', $raw);

echo 'Start date: ' . $start->format('Y-m-d') . PHP_EOL;

Calcular con DateTime é posible coa clase DateInterval. DateTime ten métodos como add() e sub() que toman un DateInterval como argumento. Non escribas código que espere o mesmo número de segundos en cada día. Tanto o horario de verán como as alteracións de zona horaria romperán esa suposición. Usa intervalos de data en cambio. Para calcular a diferenza de data usa o método diff(). Retornará un novo DateInterval, que é super fácil de mostrar.

<?php
// crea unha copia de $start e engade un mes e 6 días
$end = clone $start;
$end->add(new DateInterval('P1M6D'));

$diff = $end->diff($start);
echo 'Difference: ' . $diff->format('%m month, %d days (total: %a days)') . PHP_EOL;
// Difference: 1 month, 6 days (total: 37 days)

Podes usar comparacións estándar en obxectos DateTime:

<?php
if ($start < $end) {
    echo "Start is before the end!" . PHP_EOL;}

Un último exemplo para demostrar a clase DatePeriod. Úsase para iterar sobre eventos recorrentes. Pode tomar dous obxectos DateTime, inicio e fin, e o intervalo para o cal retornará todos os eventos entre eles.

<?php
// saída todos os xoves entre $start e $end
$periodInterval = DateInterval::createFromDateString('first thursday');
$periodIterator = new DatePeriod($start, $periodInterval, $end, DatePeriod::EXCLUDE_START_DATE);
foreach ($periodIterator as $date) {
    // saída cada data no período
    echo $date->format('Y-m-d') . ' ';
}

Unha extensión API PHP popular é Carbon. Herda todo na clase DateTime, polo que implica alteracións mínimas de código, pero as funcionalidades extra inclúen soporte de Localización, máis formas de engadir, subtraer e formatear un obxecto DateTime, ademais dun medio para probar o teu código simulando unha data e hora da túa elección.

Patróns de Deseño

Cando estás construíndo a túa aplicación é útil usar patróns comúns no teu código e patróns comúns para a estrutura xeral do teu proxecto. Usar patróns comúns é útil porque fai moito máis fácil xestionar o teu código e permite que outros desenvolvedores enteñan rapidamente como todo se encaixa xuntos.

Se usas un framework entón a maioría do código de alto nivel e estrutura do proxecto estarán baseados nese framework, polo que moitas das decisións de patróns están feitas para ti. Pero aínda depende de ti escoller os mellores patróns para seguir no código que constrúes sobre o framework. Se, por outra banda, non estás usando un framework para construír a túa aplicación entón tes que atopar os patróns que mellor se axusten ao tipo e tamaño de aplicación que estás construíndo.

Podes aprender máis sobre patróns de deseño PHP e ver exemplos funcionais en:

Traballando con UTF-8

Esta sección foi orixinalmente escrita por Alex Cabal en PHP Best Practices e foi usada como base para o noso propio consello UTF-8.

Non hai unha liña única. Sé coidadoso, detallado e consistente.

Actualmente PHP non soporta Unicode a baixo nivel. Hai formas de asegurar que as cadeas UTF-8 son procesadas ben, pero non é fácil, e require escavar en case todos os niveis da aplicación web, desde HTML a SQL a PHP. Pretendemos un resumo breve e práctico.

UTF-8 ao nivel de PHP

As operacións básicas de cadeas, como concatenar dúas cadeas e asignar cadeas a variables, non necesitan nada especial para UTF-8. Con todo, a maioría das funcións de cadeas, como strpos() e strlen(), necesitan consideración especial. Estas funcións a miúdo teñen unha contraparte mb_*: por exemplo, mb_strpos() e mb_strlen(). Estas funcións de cadeas mb_* están feitas dispoñibles para ti a través da [Extensión de Cadeas Multibyte], e están especificamente deseñadas para operar en cadeas Unicode.

Debes usar as funcións mb_* sempre que operes nunha cadea Unicode. Por exemplo, se usas substr() nunha cadea UTF-8, hai unha boa posibilidade de que o resultado inclúa algúns caracteres medio confusos. A función correcta para usar sería a contraparte multibyte, mb_substr().

A parte difícil é recordar usar as funcións mb_* en todo momento. Se esqueces incluso só unha vez, a túa cadea Unicode ten unha posibilidade de ser confusa durante o procesamento posterior.

Non todas as funcións de cadeas teñen unha contraparte mb_*. Se non hai unha para o que queres facer, entón poderías estar sen sorte.

Debes usar a función mb_internal_encoding() no cume de cada script PHP que escribas (ou no cume do teu script de inclusión global), e a función mb_http_output() xusto despois dela se o teu script está saíndo a un navegador. Definir explicitamente a codificación das túas cadeas en cada script che aforrará moitas dores de cabeza no futuro.

Ademais, moitas funcións PHP que operan en cadeas teñen un parámetro opcional permitíndoche especificar a codificación de caracteres. Debes sempre indicar explicitamente UTF-8 cando teñes a opción. Por exemplo, htmlentities() ten unha opción para codificación de caracteres, e debes sempre especificar UTF-8 se tratas con tales cadeas. Nota que desde PHP 5.4.0, UTF-8 é a codificación por defecto para htmlentities() e htmlspecialchars().

Finalmente, se estás construíndo unha aplicación distribuída e non podes estar certo de que a extensión mbstring será habilitada, entón considera usar o paquete Composer symfony/polyfill-mbstring. Isto usará mbstring se está dispoñible, e volverá a funcións non UTF-8 se non.

UTF-8 ao nivel da Base de Datos

Se o teu script PHP accede a MySQL, hai unha posibilidade de que as túas cadeas poidan ser almacenadas como cadeas non UTF-8 na base de datos mesmo se segues todas as precaucións anteriores.

Para asegurar que as túas cadeas van desde PHP a MySQL como UTF-8, asegúrate de que a túa base de datos e táboas están todas configuradas ao conxunto de caracteres e colación utf8mb4, e que usas o conxunto de caracteres utf8mb4 na cadea de conexión PDO. Vexa código de exemplo abaixo. Isto é críticamente importante.

Nota que debes usar o conxunto de caracteres utf8mb4 para soporte completo UTF-8, non o conxunto de caracteres utf8! Vexa Lectura Adicional para por que.

UTF-8 ao nivel do Navegador

Usa a función mb_http_output() para asegurar que o teu script PHP sae cadeas UTF-8 ao teu navegador.

O navegador entón necesitará ser dito pola resposta HTTP que esta páxina debería ser considerada como UTF-8. Hoxe, é común configurar o conxunto de caracteres no cabeceira da resposta HTTP así:

<?php
header('Content-Type: text/html; charset=UTF-8')

O enfoque histórico para facer iso era incluír a etiqueta <meta> charset na túa etiqueta <head> da páxina.

<?php
// Dille a PHP que estamos usando cadeas UTF-8 ata o final do script
mb_internal_encoding('UTF-8');
$utf_set = ini_set('default_charset', 'utf-8');
if (!$utf_set) {
    throw new Exception('could not set default_charset to utf-8, please ensure it\'s set on your system!');
}

// Dille a PHP que sairemos UTF-8 ao navegador
mb_http_output('UTF-8');
 
// A nosa cadea de proba UTF-8
$string = 'Êl síla erin lû e-govaned vîn.';

// Transforma a cadea dalgunha forma cunha función multibyte
// Nota como cortamos a cadea nun carácter non-Ascii para propósitos de demostración
$string = mb_substr($string, 0, 15);

// Conecta a unha base de datos para almacenar a cadea transformada
// Vexa o exemplo PDO neste documento para máis información
// Nota o `charset=utf8mb4` no Nome da Fonte de Datos (DSN)
$link = new PDO(
    'mysql:host=your-hostname;dbname=your-db;charset=utf8mb4',
    'your-username',
    'your-password',
    array(
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_PERSISTENT => false
    )
);

// Almacena a nosa cadea transformada como UTF-8 na nosa base de datos
// A túa BD e táboas están no conxunto de caracteres e colación utf8mb4, certo?
$handle = $link->prepare('insert into ElvishSentences (Id, Body, Priority) values (default, :body, :priority)');
$handle->bindParam(':body', $string, PDO::PARAM_STR);
$priority = 45;
$handle->bindParam(':priority', $priority, PDO::PARAM_INT); // dille explicitamente a pdo que espere un int
$handle->execute();

// Recupera a cadea que acabamos de almacenar para probar que foi almacenada correctamente
$handle = $link->prepare('select * from ElvishSentences where Id = :id');
$id = 7;
$handle->bindParam(':id', $id, PDO::PARAM_INT);
$handle->execute();

// Almacena o resultado nun obxecto que sairemos máis tarde no noso HTML
// Este obxecto non matará a túa memoria porque obtén os datos Just-In-Time para
$result = $handle->fetchAll(\PDO::FETCH_OBJ);

// Un exemplo wrapper para permitirche escapar datos a html
function escape_to_html($dirty){
    echo htmlspecialchars($dirty, ENT_QUOTES, 'UTF-8');
}
// Innecesario se o teu 'default_charset' xa está configurado a utf-8
header('Content-Type: text/html; charset=UTF-8'); 
?><!doctype html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>UTF-8 test page</title>
    </head>
    <body>
        <?php
        foreach($result as $row){
            escape_to_html($row->Body);  // Isto debería mostrar correctamente a nosa cadea UTF-8 transformada ao navegador
        }
        ?>
    </body>
</html>

Lectura adicional

Internacionalización (i18n) e Localización (l10n)

Descargo de responsabilidade para principiantes: i18n e l10n son numerónimos, un tipo de abreviatura onde os números son usados para acurtar palabras - no noso caso, internacionalización convértese en i18n e localización, l10n.

Primeiro de todo, necesitamos definir eses dous conceptos similares e outras cousas relacionadas:

Formas comúns de implementar

A forma máis fácil de internacionalizar software PHP é usando arquivos de array e usando esas cadeas en plantillas, como <h1><?=$TRANS['title_about_page']?></h1>. Esta forma é, con todo, dificilmente recomendada para proxectos serios, xa que presenta algúns problemas de mantemento ao longo do camiño - algúns poden aparecer no mesmo inicio, como a pluralización. Así que, por favor, non tentes isto se o teu proxecto conterá máis de un par de páxinas.

A forma máis clásica e a miúdo tomada como referencia para i18n e l10n é unha ferramenta Unix chamada gettext. Data de 1995 e aínda é unha implementación completa para traducir software. É fácil de facer funcionar, mentres aínda ten ferramentas de soporte poderosas. É sobre Gettext do que falaremos aquí. Tamén, para axudarte a non confundirte coa liña de comandos, presentaremos unha gran aplicación GUI que pode ser usada para actualizar facilmente a túa fonte l10n.

Outras ferramentas

Hai librarías comúns usadas que soportan Gettext e outras implementacións de i18n. Algunhas delas poden parecer máis fáciles de instalar ou ter funcionalidades adicionais ou formatos de arquivo i18n. Neste documento, enfocámonos nas ferramentas proporcionadas co núcleo de PHP, pero aquí listamos outras para completar:

Outros frameworks tamén inclúen módulos i18n, pero eses non están dispoñíbeis fóra das súas bases de código:

Se decides ir por unha das librarías que non proporcionan extractores, podes querer usar os formatos gettext, para que podes usar a cadea de ferramentas gettext orixinal (incluíndo Poedit) como descrito no resto do capítulo.

Gettext

Instalación

Podes necesitar instalar Gettext e a libraría PHP relacionada usando o teu xestor de paquetes, como apt-get ou yum. Despois de instalado, habilítao engadindo extension=gettext.so (Linux/Unix) ou extension=php_gettext.dll (Windows) ao teu php.ini.

Aquí tamén usaremos Poedit para crear arquivos de tradución. Probablemente o atoparás no xestor de paquetes do teu sistema; está dispoñíbel para Unix, macOS e Windows, e pode ser descargado gratis no seu sitio web tamén.

Estrutura

Tipos de arquivos

Hai tres arquivos co que xeralmente traballas mentres traballas con gettext. Os principais son os arquivos PO (Obxecto Portábel) e MO (Obxecto de Máquina), o primeiro sendo unha lista de “obxectos traducidos” lexíbeis e o segundo, o binario correspondente para ser interpretado por gettext cando fai localización. Tamén hai un arquivo POT (Plantilla), que simplemente contén todas as chaves existentes dos teus arquivos fonte, e pode ser usado como unha guía para xerar e actualizar todos os arquivos PO. Eses arquivos de plantilla non son obrigatorios: dependendo da ferramenta que estás usando para facer l10n, podes ir ben só con arquivos PO/MO. Sempre terás un par de arquivos PO/MO por linguaxe e rexión, pero só un POT por dominio.

Dominios

Hai algúns casos, en proxectos grandes, onde podes necesitar separar traducións cando as mesmas palabras transmiten significados diferentes dado un contexto. Neses casos, sepáranos en diferentes dominios. Son, basicamente, grupos nomeados de arquivos POT/PO/MO, onde o nome do arquivo é o dito dominio de tradución. Proxectos pequenos e medianos xeralmente, por simplicidade, usan só un dominio; o seu nome é arbitrario, pero usaremos “main” para os nosos exemplos de código. En proxectos Symfony, por exemplo, os dominios son usados para separar a tradución para mensaxes de validación.

Código de localidade

Unha localidade é simplemente un código que identifica unha versión dunha linguaxe. Está definido seguindo as especificacións ISO 639-1 e ISO 3166-1 alpha-2: dúas letras minúsculas para a linguaxe, opcionalmente seguidas por un subliñado e dúas letras maiúsculas identificando o país ou código rexional. Para linguaxes raras, úsanse tres letras.

Para algúns falantes, a parte do país pode parecer redundante. De feito, algunhas linguaxes teñen dialectos en diferentes países, como alemán austríaco (de_AT) ou portugués brasileiro (pt_BR). A segunda parte é usada para distinguir entre eses dialectos - cando non está presente, é tomado como unha versión “xenérica” ou “híbrida” da linguaxe.

Estrutura de directorios

Para usar Gettext, necesitaremos adherir a unha estrutura específica de carpetas. Primeiro, necesitarás seleccionar un directorio raíz arbitrario para os teus arquivos l10n no teu repositorio fonte. Dentro del, terás unha carpeta para cada localidade necesaria, e unha carpeta fixa LC_MESSAGES que conterá todos os teus pares PO/MO. Exemplo:

<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/
       └─ ...

Formas plurales

Como dixemos na introdución, linguaxes diferentes poden ter regras plurales diferentes. Con todo, gettext aforranos de este problema unha vez máis. Cando creas un novo arquivo .po, terás que declarar as regras plurales para esa linguaxe, e as pezas traducidas que son sensibles ao plural terán unha forma diferente para cada unha desas regras. Cando chamas Gettext no código, terás que especificar o número relacionado coa frase, e funcionará a forma correcta para usar - mesmo usando substitución de cadea se é necesario.

As regras plurales inclúen o número de plurais dispoñíbeis e unha proba booleana con n que definiría en que regra o número dado cae (comezando a conta con 0). Por exemplo:

Agora que entendiches a base de como funcionan as regras plurales - e se non o fixeches, por favor mira unha explicación máis profunda no tutorial de LingoHub -, podes querer copiar as que necesitas dunha lista en lugar de escribilas a man.

Cando chamas Gettext para facer localización en frases con contadores, terás que proporcionarlle o número relacionado tamén. Gettext funcionará que regra debería estar en efecto e usar a versión localizada correcta. Necesitarás incluír no arquivo .po unha frase diferente para cada regra plural definida.

Exemplo de implementación

Despois de toda esa teoría, vamos facer algo práctico. Aquí hai un extracto dun arquivo .po - non te preocupes co seu formato, senón co contido xeral; aprenderás como editalo facilmente máis tarde:

msgid ""
msgstr ""
"Language: pt_BR\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

msgid "We are now translating some strings"
msgstr "Nós estamos traduzindo algumas strings agora"

msgid "Hello %1$s! Your last visit was on %2$s"
msgstr "Olá %1$s! Sua última visita foi em %2$s"

msgid "Only one unread message"
msgid_plural "%d unread messages"
msgstr[0] "Só uma mensagem não lida"
msgstr[1] "%d mensagens não lidas"

A primeira sección funciona como un cabeceira, tendo o msgid e msgstr especialmente baleiros. Describe a codificación do arquivo, formas plurales e outras cousas que son menos relevantes. A segunda sección traduce unha cadea simple do inglés ao portugués brasileiro, e a terceira fai o mesmo, pero aproveitando a substitución de cadea de sprintf para que a tradución poida conter o nome do usuario e data de visita. A última sección é un exemplo de formas de pluralización, mostrando a versión singular e plural como msgid en inglés e as súas traducións correspondentes como msgstr 0 e 1 (seguindo o número dado pola regra plural). Alí, a substitución de cadea é usada tamén para que o número poida ser visto directamente na frase, usando %d. As formas plurales sempre teñen dous msgid (singular e plural), polo que é aconsellado non usar unha linguaxe complexa como a fonte de tradución.

Discusión sobre chaves l10n

Como podes ter notado, estamos usando como ID fonte a frase real en inglés. Ese msgid é o mesmo usado a través de todos os teus arquivos .po, significando que outras linguaxes terán o mesmo formato e os mesmos campos msgid pero liñas msgstr traducidas.

Falando sobre chaves de tradución, hai dúas “escolas” principais aquí:

  1. msgid como unha frase real. As principais vantaxes son:
    • se hai pezas do software non traducidas en calquera linguaxe dada, a chave mostrada aínda manterá algún significado. Exemplo: se aconteces traducir de memoria do inglés ao español pero necesitas axuda para traducir ao francés, podes publicar a nova páxina con frases francesas faltantes, e partes do sitio web serían mostradas en inglés en cambio;
    • é moito máis fácil para o tradutor entender que está pasando e facer unha tradución adecuada baseada no msgid;
    • dache l10n “gratis” para unha linguaxe - a fonte;
    • A única desvantaxe: se necesitas cambiar o texto real, necesitarías substituir o mesmo msgid a través de varios arquivos de linguaxe.
  2. msgid como unha chave única e estruturada. Describiría o papel da frase na aplicación dunha forma estruturada, incluíndo a plantilla ou parte onde a cadea está localizada en lugar do seu contido.
    • é unha gran forma de ter o código organizado, separando o contido de texto da lóxica da plantilla.
    • con todo, iso podería traer problemas ao tradutor que perdería o contexto. Un arquivo de linguaxe fonte sería necesario como base para outras traducións. Exemplo: o desenvolvedor idealmente tería un arquivo en.po, que os tradutores lerían para entender que escribir en fr.po por exemplo.
    • as traducións faltantes mostrarían chaves sen significado na pantalla (top_menu.welcome en lugar de Hello there, User! na dita páxina francesa non traducida). Iso é bo xa que forzaría a tradución a ser completa antes de publicar - con todo, malo xa que os problemas de tradución serían notablemente terribles na interface. Algunhas librarías, con todo, inclúen unha opción para especificar unha linguaxe dada como “fallback”, tendo un comportamento similar ao outro enfoque.

O manual de Gettext favorece o primeiro enfoque xa que, en xeral, é máis fácil para tradutores e usuarios en caso de problemas. É así como tamén traballaremos aquí. Con todo, a documentación de Symfony favorece tradución baseada en palabras clave, para permitir cambios independentes de todas as traducións sen afectar as plantillas tamén.

Uso cotián

Nunha aplicación típica, usarías algunhas funcións Gettext mentres escribes texto estático nas túas páxinas. Esas frases entón aparecerían en arquivos .po, serían traducidas, compiladas en arquivos .mo e entón, usadas por Gettext cando renderiza a interface real. Dado iso, vamos atar xuntos o que discutimos ata agora nun exemplo paso a paso:

1. Un arquivo de plantilla de exemplo, incluíndo algunhas chamadas gettext diferentes

<?php include 'i18n_setup.php' ?>
<div id="header">
    <h1><?=sprintf(gettext('Welcome, %s!'), $name)?></h1>
    <!-- código indentado desta forma só para lexibilidade -->
    <?php if ($unread): ?>
        <h2><?=sprintf(
            ngettext('Only one unread message',
                     '%d unread messages',
                     $unread),
            $unread)?>
        </h2>
    <?php endif ?>
</div>

<h1><?=gettext('Introduction')?></h1>
<p><?=gettext('We\'re now translating some strings')?></p>

2. Un arquivo de configuración de exemplo (i18n_setup.php como usado arriba), seleccionando a localidade correcta e configurando Gettext

<?php
/**
 * Verifica se a localidade dada $locale é soportada no proxecto
 * @param string $locale
 * @return bool
 */
function valid($locale) {
   return in_array($locale, ['en_US', 'en', 'pt_BR', 'pt', 'es_ES', 'es']);
}

//configurando a localidade fonte/por defecto, para propósitos informativos
$lang = 'en_US';

if (isset($_GET['lang']) && valid($_GET['lang'])) {
    // a localidade pode ser cambiada a través da query-string
    $lang = $_GET['lang'];    //deberías sanitizar isto!
    setcookie('lang', $lang); //está almacenado nunha cookie para que poida ser reusado
} elseif (isset($_COOKIE['lang']) && valid($_COOKIE['lang'])) {
    // se a cookie está presente en cambio, só mantémola
    $lang = $_COOKIE['lang']; //deberías sanitizar isto!
} elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
    // por defecto: busca as linguaxes que o navegador di que o 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í definimos a localidade do sistema global dada a linguaxe atopada
putenv("LANG=$lang");

// isto pode ser útil para funcións de data (LC_TIME) ou formateado de diñeiro (LC_MONETARY), por exemplo
setlocale(LC_ALL, $lang);

// isto fará que Gettext busque en ../locales/<lang>/LC_MESSAGES/main.mo
bindtextdomain('main', '../locales');

// indica en que codificación o arquivo debería ser lido
bind_textdomain_codeset('main', 'UTF-8');

// se a túa aplicación ten dominios adicionais, como citado antes, deberías vinculalos aquí tamén
bindtextdomain('forum', '../locales');
bind_textdomain_codeset('forum', 'UTF-8');

// aquí indicamos o dominio por defecto ao que as chamadas gettext() responderán
textdomain('main');

// isto buscaría a cadea en forum.mo en lugar de main.mo
// echo dgettext('forum', 'Welcome back!');
?>

3. Preparando tradución para a primeira execución

Unha das grandes vantaxes que Gettext ten sobre paquetes i18n de frameworks personalizados é o seu formato de arquivo extenso e poderoso. “¡Oh home, iso é bastante difícil de entender e editar a man, un array simple sería máis fácil!” Non te equivoques, aplicacións como Poedit están aquí para axudar - moito. Podes obter o programa do seu sitio web, é gratis e está dispoñíbel para todas as plataformas. É unha ferramenta bastante fácil de acostumbrarse, e unha moi poderosa ao mesmo tempo - usando todas as funcionalidades que Gettext ten dispoñíbeis. Esta guía está baseada en PoEdit 1.8.

Na primeira execución, deberías seleccionar “File > New…” do menú. Serás preguntado directamente pola linguaxe: aquí podes seleccionar/filtrar a linguaxe que queres traducir, ou usar ese formato que mencionamos antes, como en_US ou pt_BR.

Agora, garda o arquivo - usando esa estrutura de directorios que mencionamos tamén. Entón deberías facer clic en “Extract from sources”, e aquí configurarás varias configuracións para as tarefas de extracción e tradución. Poderás atopar todas esas máis tarde a través de “Catalog > Properties”:

Despois de establecer eses puntos executará unha busca a través dos teus arquivos fonte para atopar todas as chamadas de localización. Despois de cada busca PoEdit mostrará un resumo do que foi atopado e do que foi eliminado dos arquivos fonte. As novas entradas serán alimentadas baleiras na táboa de tradución, e comezarás a escribir as versións localizadas desas cadeas. Gardao e un arquivo .mo será (re)compilado na mesma carpeta e ta-dah: o teu proxecto está internacionalizado.

4. Traducindo cadeas

Como podes ter notado antes, hai dous tipos principais de cadeas localizadas: simples e aquelas con formas plurales. As primeiras simplemente teñen dúas caixas: cadea fonte e cadea localizada. A cadea fonte non pode ser modificada xa que Gettext/Poedit non inclúen os poderes para alterar os teus arquivos fonte - deberías cambiar a fonte en si e rebuscar os arquivos. Consello: podes facer clic dereito nunha liña de tradución e che dará unha pista cos arquivos fonte e liñas onde esa cadea está sendo usada. Por outra banda, as cadeas de forma plural inclúen dúas caixas para mostrar as dúas cadeas fonte, e pestanas para que poidas configurar as diferentes formas finais.

Sempre que cambies as túas fontes e necesites actualizar as traducións, só fai clic en Refresh e Poedit rebuscará o código, eliminando entradas non existentes, fusionando as que cambiaron e engadindo novas. Tamén pode tentar adiviñar algunhas traducións, baseadas noutras que fixeches. Esas adiviñacións e as entradas cambiadas recibirán un marcador “Fuzzy”, indicando que necesita revisión, aparecendo dourado na lista. Tamén é útil se tes un equipo de tradución e alguén tenta escribir algo do que non están seguros: só marca Fuzzy, e alguén máis revisará máis tarde.

Finalmente, é aconsellado deixar “View > Untranslated entries first” marcado, xa que che axudará moito a non esquecer ningunha entrada. Desde ese menú, tamén podes abrir partes da UI que permiten deixar información contextual para tradutores se é necesario.

Consellos e Trucos

Posíbeis problemas de caché

Se estás executando PHP como un módulo en Apache (mod_php), podes enfrontarte problemas co arquivo .mo sendo cacheado. Acontece a primeira vez que é lido, e entón, para actualizalo, podes necesitar reiniciar o servidor. En Nginx e PHP5 xeralmente leva só un par de refrescos de páxina para refrescar o caché de tradución, e en PHP7 raramente é necesario.

Funcións auxiliares adicionais

Como preferido por moita xente, é máis fácil usar _() en lugar de gettext(). Moitas librarías i18n personalizadas de frameworks usan algo similar a t() tamén, para facer o código traducido máis curto. Con todo, esa é a única función que ten un atallo. Podes querer engadir no teu proxecto algunhas outras, como __() ou _n() para ngettext(), ou quizais un elegante _r() que uniría chamadas gettext() e sprintf(). Outras librarías, como Gettext de php-gettext tamén proporcionan funcións auxiliares como estas.

Neses casos, necesitarás instruír a utilidade Gettext sobre como extraer as cadeas desas novas funcións. Non te asustes; é moi fácil. É só un campo no arquivo .po, ou unha pantalla de Configuracións en Poedit. No editor, esa opción está dentro de “Catalog > Properties > Source keywords”. Lembra: Gettext xa sabe as funcións por defecto para moitas linguaxes, así que non te asustes se esa lista parece baleira. Necesitas incluír alí as especificacións desas novas funcións, seguindo un formato específico:

Despois de incluír esas novas regras no arquivo .po, unha nova busca traerá as túas novas cadeas tan fácil como antes.

Referencias

Back to Top

Inxección de Dependencias

Desde Wikipedia:

A inxección de dependencias é un patrón de deseño de software que permite a eliminación de dependencias codificadas a man e fai posible cambialas, sexa en tempo de execución ou tempo de compilación.

Esta cita fai que o concepto soe moito máis complicado do que realmente é. A Inxección de Dependencias é proporcionar a un compoñente as súas dependencias a través de inxección de construtor, chamadas de método ou a configuración de propiedades. É tan simple como iso.

Concepto Básico

Podemos demostrar o concepto cun exemplo simple, pero inxenuo.

Aquí temos unha clase Database que require un adaptador para falar coa base de datos. Instanciamos o adaptador no construtor e creamos unha dependencia dura. Isto fai que as probas sexan difíciles e significa que a clase Database está moi estreitamente acoplada ao adaptador.

<?php
namespace Database;

class Database
{
    protected $adapter;

    public function __construct()
    {
        $this->adapter = new MySqlAdapter;
    }
}

class MysqlAdapter {}

Este código pode ser refactorizado para usar Inxección de Dependencias e polo tanto soltar a dependencia. Aquí, inxectamos a dependencia nun construtor e usamos a promoción de propiedades do construtor para que estea dispoñible como unha propiedade a través da clase:

<?php
namespace Database;

class Database
{
    public function __construct(protected MySqlAdapter $adapter)
    {
    }
}

class MysqlAdapter {}

Agora estamos dando á clase Database a súa dependencia en lugar de creala ela mesma. Poderíamos mesmo crear un método que aceptase un argumento da dependencia e a configurase dese xeito, ou se a propiedade $adapter fose public poderíamos configurala directamente.

Problema Complexo

Se algunha vez leste sobre Inxección de Dependencias entón probablemente viste os termos “Inversión de Control” ou “Principio de Inversión de Dependencias”. Estes son os problemas complexos que a Inxección de Dependencias resolve.

Inversión de Control

A Inversión de Control é como di, “invertendo o control” dun sistema mantendo o control organizacional completamente separado dos nosos obxectos. En termos de Inxección de Dependencias, isto significa soltar as nosas dependencias controlando e instanciándoas noutro lugar do sistema.

Durante anos, os frameworks PHP estiveron logrando Inversión de Control, con todo, a pregunta converteuse en, que parte do control estamos invertendo, e onde? Por exemplo, os frameworks MVC xeralmente proporcionarían un super obxecto ou controlador base que outros controladores deben estender para obter acceso ás súas dependencias. Isto é Inversión de Control, con todo, en lugar de soltar dependencias, este método simplemente móveas.

A Inxección de Dependencias permite-nos resolver este problema máis elegantemente só inxectando as dependencias que necesitamos, cando as necesitamos, sen a necesidade de calquera dependencia codificada a man.

S.O.L.I.D.

Principio de Responsabilidade Única

O Principio de Responsabilidade Única é sobre actores e arquitectura de alto nivel. Afirma que “Unha clase debería ter só unha razón para cambiar.” Isto significa que cada clase debería ter responsabilidade sobre unha única parte da funcionalidade proporcionada polo software. O maior beneficio deste enfoque é que permite mellorada reutilizabilidade do código. Ao deseñar a nosa clase para facer só unha cousa, podemos usala (ou re-usala) en calquera outro programa sen cambiala.

Principio Aberto/Pechado

O Principio Aberto/Pechado é sobre deseño de clases e extensións de funcionalidades. Afirma que “As entidades de software (clases, módulos, funcións, etc.) deberían estar abertas para extensión, pero pechadas para modificación.” Isto significa que deberíamos deseñar os nosos módulos, clases e funcións dun xeito que cando se necesite unha nova funcionalidade, non deberíamos modificar o noso código existente senón escribir novo código que será usado polo código existente. Practicamente falando, isto significa que deberíamos escribir clases que implementen e adhiran a interfaces, entón type-hint contra esas interfaces en lugar de clases específicas.

O maior beneficio deste enfoque é que podemos moi facilmente estender o noso código con soporte para algo novo sen ter que modificar código existente, significando que podemos reducir o tempo de QA, e o risco de impacto negativo na aplicación é substancialmente reducido. Podemos desplegar novo código, máis rápido, e con máis confianza.

Principio de Substitución de Liskov

O Principio de Substitución de Liskov é sobre subtipado e herdanza. Afirma que “As clases fillas nunca deberían romper as definicións de tipo da clase pai.” Ou, nas palabras de Robert C. Martin, “Os subtipos deben ser substituíbles polos seus tipos base.”

Por exemplo, se temos unha interface FileInterface que define un método embed(), e temos clases Audio e Video que ambas implementan a interface FileInterface, entón podemos esperar que o uso do método embed() sempre faga a cousa que pretendemos. Se máis tarde creamos unha clase PDF ou unha clase Gist que implementan a interface FileInterface, xa saberemos e entenderemos que fará o método embed(). O maior beneficio deste enfoque é que temos a capacidade de construír programas flexibles e facilmente configurábeis, porque cando cambiamos un obxecto dun tipo (ex., FileInterface) por outro non necesitamos cambiar nada máis no noso programa.

Principio de Segregación de Interfaces

O Principio de Segregación de Interfaces (ISP) é sobre comunicación lóxica-de-negocio-a-clientes. Afirma que “Ningún cliente debería ser forzado a depender de métodos que non usa.” Isto significa que en lugar de ter unha única interface monolítica que todas as clases conformes necesitan implementar, deberíamos en cambio proporcionar un conxunto de interfaces máis pequenas, específicas de concepto que unha clase conforme implementa unha ou máis.

Por exemplo, unha clase Car ou Bus estaría interesada nun método steeringWheel(), pero unha clase Motorcycle ou Tricycle non. Inversamente, unha clase Motorcycle ou Tricycle estaría interesada nun método handlebars(), pero unha clase Car ou Bus non. Non hai necesidade de ter todos estes tipos de vehículos implementando soporte tanto para steeringWheel() como para handlebars(), polo que deberíamos romper a interface fonte.

Principio de Inversión de Dependencias

O Principio de Inversión de Dependencias é sobre eliminar enlaces duros entre clases discretas para que nova funcionalidade poida ser aproveitada pasando unha clase diferente. Afirma que un debería “Depender de Abstraccións. Non depender de concrecións.”. Simplemente posto, isto significa que as nosas dependencias deberían ser interfaces/contratos ou clases abstractas en lugar de implementacións concretas. Podemos facilmente refactorizar o exemplo anterior para seguir este principio.

<?php
namespace Database;

class Database
{
    public function __construct(protected AdapterInterface $adapter)
    {
    }
}

interface AdapterInterface {}

class MysqlAdapter implements AdapterInterface {}

Hai varios beneficios para a clase Database agora dependendo dunha interface en lugar dunha concreción.

Considera que estamos a traballar nun equipo e o adaptador está sendo traballado por un colega. No noso primeiro exemplo, teríamos que esperar por dito colega para rematar o adaptador antes de que poidamos mockearlo adecuadamente para as nosas probas unitarias. Agora que a dependencia é unha interface/contrato podemos felizmente mockear esa interface sabendo que o noso colega construirá o adaptador baseado nese contrato.

Un beneficio aínda maior para este método é que o noso código agora é moito máis escalábel. Se un ano máis tarde decidimos que queremos migrar a un tipo diferente de base de datos, podemos escribir un adaptador que implemente a interface orixinal e inxecte iso en cambio, non se requiría máis refactorización xa que podemos asegurar que o adaptador segue o contrato establecido pola interface.

Contenedores

A primeira cousa que deberías entender sobre os Contenedores de Inxección de Dependencias é que non son a mesma cousa que a Inxección de Dependencias. Un contenedor é unha utilidade de conveniencia que nos axuda a implementar Inxección de Dependencias, con todo, poden ser e a miúdo son mal usados para implementar un anti-patrón, Localización de Servizos. Inxectar un contenedor DI como un Localizador de Servizos nas túas clases argumentablemente crea unha dependencia máis dura no contenedor que a dependencia que estás substituíndo. Tamén fai o teu código moito menos transparente e finalmente máis difícil de probar.

A maioría dos frameworks modernos teñen o seu propio Contenedor de Inxección de Dependencias que permite que conectes as túas dependencias xuntas a través de configuración. O que isto significa na práctica é que podes escribir código de aplicación que é tan limpo e desacoplado como o framework no que está construído.

Lecturas adicionais

Back to Top

Bases de Datos

Moitas veces o teu código PHP usará unha base de datos para persistir información. Tes unhas poucas opcións para conectar e interactuar coa túa base de datos. A opción recomendada ata PHP 5.1.0 era usar drivers nativos como mysqli, pgsql, mssql, etc.

Os drivers nativos son excelentes se só estás usando unha base de datos na túa aplicación, pero se, por exemplo, estás usando MySQL e un pouco de MSSQL, ou necesitas conectar a unha base de datos Oracle, entón non poderás usar os mesmos drivers. Necesitarás aprender unha API completamente nova para cada base de datos — e iso pode volverse ridículo.

Extensión MySQL

A extensión mysql para PHP é increíblemente antiga e foi suplantada por dúas outras extensións:

Non só o desenvolvemento se detivo hai moito tempo mysql, foi eliminado oficialmente en PHP 7.0.

Para asegurar a busca nas túas opcións de php.ini para ver que módulo estás usando, unha opción é buscar mysql_* no editor que escollas. Se algunha función como mysql_connect() e mysql_query() aparecen, entón mysql está en uso.

Mesmo se aínda non estás a usar PHP 7.x ou posterior, non considerar esta actualización canto antes levará a maiores dificultades cando se produza a actualización de PHP. A mellor opción é substituír o uso de mysql por mysqli ou PDO nas túas aplicacións dentro dos teus propios programas de desenvolvemento para non ter présas máis tarde.

Se estás a actualizar desde mysql a mysqli, coidado coas guías de actualización preguiceiras que suxiren que podes simplemente atopar e substituír mysql_* con mysqli_*. Non só é unha simplificación excesiva, senón que tamén pasa por alto as vantaxes que ofrece mysqli, como a vinculación de parámetros, que tamén se ofrece en PDO.

Extensión PDO

PDO é unha libraría de abstracción de conexión a bases de datos — integrada en PHP desde 5.1.0 — que proporciona unha interface común para falar con moitas bases de datos diferentes. Por exemplo, podes usar código basicamente idéntico para interactuar con MySQL ou 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 non traducirá as túas consultas SQL ou emulará funcionalidades que faltan; é puramente para conectar a múltiples tipos de base de datos coa mesma API.

Máis importante, PDO permite inxectar de forma segura entrada estraña (ex. IDs) nas túas consultas SQL sen preocuparte sobre ataques de inxección SQL da base de datos. Isto é posible usando statements PDO e parámetros vinculados.

Asumamos que un script PHP recibe un ID numérico como parámetro de consulta. Este ID debería ser usado para obter un rexistro de usuario desde unha base de datos. Esta é a forma incorrecta de facelo:

<?php
$pdo = new PDO('sqlite:/path/db/users.db');
$pdo->query("SELECT name FROM users WHERE id = " . $_GET['id']); // <-- NON!

Este é código terrible. Estás inserindo un parámetro de consulta bruto nunha consulta SQL. Isto che levará a ser hackeado nun instante, usando unha práctica chamada SQL Injection. Só imaxina se un hacker pasa un parámetro id inventivo chamando unha URL como http://domain.com/?id=1%3BDELETE+FROM+users. Isto establecerá a variable $_GET['id'] a 1; DELETE FROM users que eliminará todos os teus usuarios! En cambio, deberías sanitizar a entrada do ID usando parámetros vinculados 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); // <-- filtra os teus datos primeiro (ver [Filtrado de Datos](#data_filtering)), especialmente importante para INSERT, UPDATE, etc.
$stmt->bindParam(':id', $id, PDO::PARAM_INT); // <-- Automaticamente sanitizado para SQL por PDO
$stmt->execute();

Este é código correcto. Usa un parámetro vinculado nun statement PDO. Isto escapa a entrada estraña do ID antes de que sexa introducida na base de datos previndo potenciais ataques de inxección SQL.

Para escrituras, como INSERT ou UPDATE, é especialmente crítico aínda filtrar os teus datos primeiro e sanitizalos para outras cousas (eliminación de etiquetas HTML, JavaScript, etc). PDO só o sanitizará para SQL, non para a túa aplicación.

Tamén deberías ser consciente de que as conexións a bases de datos usan recursos e non era inaudito ter recursos esgotados se as conexións non se pechaban implicitamente, con todo isto era máis común noutras linguaxes. Usando PDO podes pechar implicitamente a conexión destruíndo o obxecto asegurándote de que todas as referencias restantes a el son eliminadas, ex. establecidas a NULL. Se non fas isto explicitamente, PHP pechará automaticamente a conexión cando o teu script termine - a menos que por suposto esteas usando conexións persistentes.

Interacción con bases de datos

Cando os desenvolvedores comezan a aprender PHP, a miúdo acaban mesturando a interacción da base de datos coa súa lóxica de presentación, usando código que podería ter este aspecto:

<ul>
<?php
foreach ($db->query('SELECT * FROM table') as $row) {
    echo "<li>".$row['field1']." - ".$row['field1']."</li>";
}
?>
</ul>

Esta é unha mala práctica por moitos motivos, principalmente porque é difícil de depurar, difícil de probar, difícil de ler e vai xerar moitos campos se non se lle pon un límite.

Aínda que hai moitas outras solucións para facelo, dependendo de se prefires OOP ou programación funcional - debe haber algún elemento de separación.

Considera o paso 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!!
}

Ese é un bo comezo. Pon eses dous elementos en dous arquivos diferentes e terás unha separación clara.

Crea unha clase para colocar ese método e terás un “Modelo” - “Model”-. Crea un sinxelo arquivo .php para poñer a lóxica da presentación e tes un “Vista” - “View”-, que é case MVC - unha arquitectura POO común para a maioría dos frameworks.

foo.php

<?php
$db = new PDO('mysql:host=localhost;dbname=testdb;charset=utf8mb4', 'username', 'password');

// Fai que o teu modelo estea dispoñible
include 'models/FooModel.php';

// Crear unha instancia
$fooModel = new FooModel($db);
// Obtén a lista de Foos
$fooList = $fooModel->getAllFoos();

// Mostra a 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 ?>

Isto é esencialmente o mesmo que o que a maioría dos frameworks modernos están a facer, aínda que sexa un pouco máis manual. Podes non precisar facer todo isto cada vez, pero combinar demasiada lóxica de presentación e interacción coa base de datos pode ser un problema real se algún día queres unha proba unitaria unit-test da túa aplicación.

Capas de abstracción

Moitos marcos de traballo proporcionan a súa propia capa de abstracción que pode ou non estar enriba de PDO. Estes a miúdo emulan características para un sistema de bases de datos que faltan noutro envolvendo as túas consultas en métodos PHP, dándoche unha abstracción real da base de datos en lugar de só a abstracción de conexión que proporciona PDO. Isto, por suposto, engadirá un pouco de sobrecarga, pero se estás a crear unha aplicación portátil que necesita funcionar con MySQL, PostgreSQL e SQLite entón un pouco de sobrecarga pagará a pena polo ben da limpeza do código.

Algunhas capas de abstracción foron construídas usando os estándares de espazo de nomes PSR-0 ou PSR-4, polo que se poden instalar en calquera aplicación que se desexe:

Back to Top

Plantillas

As plantillas proporcionan unha forma conveniente de separar a túa lóxica de controlador e dominio da túa lóxica de presentación. As plantillas tipicamente conteñen o HTML da túa aplicación, pero tamén poden ser usadas para outros formatos, como XML. As plantillas a miúdo son referidas como “vistas”, que forman parte do segundo compoñente do patrón de arquitectura de software modelo–vista–controlador (MVC).

Beneficios

O principal beneficio de usar plantillas é a clara separación que crean entre a lóxica de presentación e o resto da túa aplicación. As plantillas teñen a única responsabilidade de mostrar contido formateado. Non son responsables de búsqueda de datos, persistencia ou outras tarefas máis complexas. Isto leva a código máis limpo e lexíbel que é especialmente útil nun ambiente de equipo onde os desenvolvedores traballan no código do lado do servidor (controladores, modelos) e os deseñadores traballan no código do lado do cliente (marcado).

As plantillas tamén melloran a organización do código de presentación. As plantillas tipicamente son colocadas nunha carpeta “views”, cada unha definida dentro dun único arquivo. Este enfoque fomenta a reutilización de código onde bloques máis grandes de código son rotos en pezas máis pequenas e reutilizábeis, a miúdo chamadas parciais. Por exemplo, o cabeceira e pé do teu sitio poden ser definidos como plantillas, que entón son incluídas antes e despois de cada plantilla de páxina.

Finalmente, dependendo da libraría que uses, as plantillas poden ofrecer máis seguridade escapando automaticamente o contido xerado polo usuario. Algunhas librarías incluso ofrecen sand-boxing, onde os deseñadores de plantillas só teñen acceso a variables e funcións de lista branca.

Modelos PHP sinxelos

Os modelos PHP sinxelos son simplemente modelos que usan código PHP nativo. Son unha elección natural xa que PHP é en realidade unha linguaxe de modelos en si mesma. Iso simplemente significa que podes combinar código PHP dentro doutro código, como HTML. Isto é beneficioso para os desenvolvedores de PHP xa que non hai que aprender unha nova sintaxe, coñecen as funcións dispoñibles para eles e os seus editores de código xa teñen incorporado o resaltado de sintaxe PHP e o autocompletado. Ademais, os modelos PHP sinxelos tenden a ser moi rápidos xa que non se require ningunha etapa de compilación.

Todos os frameworks PHP modernos empregan algún tipo de sistema de modelos, a maioría dos cales usan PHP simple por defecto. Fóra dos frameworks, librarías como Plates ou Aura.View facilitan o traballo con modelos PHP simples ao ofrecer funcionalidades de modelos modernas como herdanza, deseños e extensións.

Exemplo simple de un modelo PHP

Usando a libraría 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') ?>

Exemplo de plantilla PHP sinxel usando herencia

Usando a libraría 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>

Modelos Compilados

Aínda que PHP evolucionou converténdose nunha linguaxe madura e orientada a obxectos, non mellorou moito como linguaxe de modelado. Os modelos compilados, como Twig, Brainy ou Smarty*, cubren esta carencia ofrecendo unha nova sintaxe deseñada especificamente para modelado. Desde escape automático, até herdanza e estruturas de control simplificadas, os modelos compilados están pensados para ser máis doados de escribir, máis limpos de ler e máis seguros de usar. Estes modelos poden incluso compartirse entre diferentes linguaxes, sendo Mustache un bo exemplo disto. Xa que estes modelos deben ser compilados, hai unha lixeira penalización no rendemento, non obstante é mínima cando se usa unha caché axeitada.

*Aínda que Smarty ofrece escape automático, esta característica NON está activada por defecto.

Exemplo sinxelo dun modelo compilado

Usando a libraría Twig.

{% include 'header.html' with {'title': 'User Profile'} %}

<h1>User Profile</h1>
<p>Hello, {{ name }}</p>

{% include 'footer.html' %}

Exemplo de modelos compilados mediante herdanza

Usando a libraría 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 %}

Lecturas adicionais

Artigos e titoriais

Librarías

Back to Top

Erros e Excepcións

Erros

En moitas linguaxes de programación “pesadas en excepcións”, sempre que algo vai mal lanzarase unha excepción. Isto é certamente unha forma viable de facer as cousas, pero PHP é unha linguaxe de programación “lixeira en excepcións”. Aínda que ten excepcións e máis do núcleo está a comezar a usalas cando traballa con obxectos, a maioría do propio PHP tentará continuar procesando independentemente do que aconteza, a menos que ocorra un erro fatal.

Por exemplo:

$ php -a
php > echo $foo;
Notice: Undefined variable: foo in php shell code on line 1

Isto é só un erro de aviso, e PHP continuará felizmente. Isto pode ser confuso para aqueles que veñen de linguaxes “pesadas en excepcións”, porque referenciar unha variable faltante en Python por exemplo lanzará unha excepción:

$ python
>>> print foo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined

A única diferenza real é que Python se asustará por calquera cousa pequena, para que os desenvolvedores poidan estar super seguros de que calquera problema potencial ou caso extremo é capturado, mentres que PHP continuará procesando a menos que algo extremo aconteza, no cal punto lanzará un erro e o reportará.

Severidade do Erro

PHP ten varios niveis de severidade de erro. Os tres tipos máis comúns de mensaxes son erros, avisos e advertencias. Estes teñen diferentes niveis de severidade; E_ERROR, E_NOTICE, e E_WARNING. Os erros son erros de execución fatais e son xeralmente causados por fallos no teu código e necesitan ser arranxados xa que causarán que PHP pare de executar. Os avisos son mensaxes consultivas causadas por código que pode ou non causar problemas durante a execución do script, a execución non se detén. As advertencias son erros non fatais, a execución do script non se deterrá.

Outro tipo de mensaxe de erro reportada en tempo de compilación son as mensaxes E_STRICT. Estas mensaxes son usadas para suxerir cambios ao teu código para axudar a asegurar mellor interoperabilidade e compatibilidade cara adiante con versións próximas de PHP.

Cambiando o Comportamento de Reporte de Erros de PHP

O Reporte de Erros pode ser cambiado usando configuracións de PHP e/ou chamadas de función PHP. Usando a función integrada de PHP error_reporting() podes establecer o nivel de erros para a duración da execución do script pasando unha das constantes de nivel de erro predefinidas, significando que se só queres ver Erros e Advertencias - pero non Avisos - entón podes configurar iso:

<?php
error_reporting(E_ERROR | E_WARNING);

Tamén podes controlar se os erros son mostrados na pantalla (bo para desenvolvemento) ou ocultos, e rexistrados (bo para produción). Para máis información sobre isto consulta a sección Reporte de Erros.

Supresión de Erro en Liña

Tamén podes dicirlle a PHP que suprima erros específicos co Operador de Control de Erro @. Pós este operador no inicio dunha expresión, e calquera erro que sexa un resultado directo da expresión é silenciado.

<?php
echo @$foo['bar'];

Isto sairá $foo['bar'] se existe, pero simplemente retornará un null e non imprimirá nada se a variable $foo ou a chave 'bar' non existe. Sen o operador de control de erro, esta expresión podería crear un PHP Notice: Undefined variable: foo ou PHP Notice: Undefined index: bar erro.

Isto podería parecer unha boa idea, pero hai algúns tradeoffs desexables. PHP manexa expresións usando un @ dunha forma menos performante que expresións sen un @. A optimización prematura pode ser a raíz de todos os argumentos de programación, pero se o rendemento é particularmente importante para a túa aplicación/libraría é importante entender as implicacións de rendemento do operador de control de erro.

En segundo lugar, o operador de control de erro completamente traga o erro. O erro non é mostrado, e o erro non é enviado ao rexistro de erros. Tamén, sistemas PHP de stock/produción non teñen forma de desactivar o operador de control de erro. Mentres podes estar correcto que o erro que estás vendo é inofensivo, un erro diferente, menos inofensivo será igual de silencioso.

Se hai unha forma de evitar o operador de supresión de erro, deberías consideralo. Por exemplo, o noso código anterior podería ser reescrito así:

<?php
// Operador de Coalescencia Nula
echo $foo['bar'] ?? '';

Unha instancia onde a supresión de erro podería ter sentido é onde fopen() falla ao atopar un arquivo para cargar. Poderías verificar a existencia do arquivo antes de tentar cargalo, pero se o arquivo é eliminado despois da verificación e antes do fopen() (que podería soar imposible, pero pode acontecer) entón fopen() retornará false e lanzará un erro. Isto é potencialmente algo que PHP debería resolver, pero é un caso onde a supresión de erro podería parecer a única solución válida.

Antes mencionamos que non hai forma nun sistema PHP de stock de desactivar o operador de control de erro. Con todo, Xdebug ten unha configuración ini xdebug.scream que desactivará o operador de control de erro. Podes establecer isto a través do teu arquivo php.ini co seguinte.

xdebug.scream = On

Tamén podes establecer este valor en tempo de execución coa función ini_set

<?php
ini_set('xdebug.scream', '1')

Isto é máis útil cando estás depurando código e sospeitas que un erro informativo está suprimido. Usa scream con coidado, e como unha ferramenta de depuración temporal. Hai moito código de libraría PHP que pode non funcionar co operador de control de erro desactivado.

ErrorException

PHP é perfectamente capaz de ser unha linguaxe de programación “pesada en excepcións”, e só require unhas poucas liñas de código para facer o cambio. Basicamente podes lanzar os teus “erros” como “excepcións” usando a clase ErrorException, que estende a clase Exception.

Esta é unha práctica común implementada por un gran número de frameworks modernos como Symfony e Laravel. En modo debug (ou modo dev) ambos os frameworks mostrarán unha stack trace agradábel e limpa.

Tamén hai algúns paquetes dispoñibles para mellor manexo e reporte de erros e excepcións. Como Whoops!, que ven coa instalación por defecto de Laravel e pode ser usado en calquera framework tamén.

Ao lanzar erros como excepcións en desenvolvemento podes manexalos mellor que o resultado usual, e se ves unha excepción durante o desenvolvemento podes envolvela nunha declaración catch con instrucións específicas sobre como manexar a situación. Cada excepción que capturas instantaneamente fai a túa aplicación un pouco máis robusta.

Máis información sobre isto e detalles sobre como usar ErrorException con manexo de erros pode ser atopada en Clase ErrorException.

Excepcións

As excepcións son unha parte estándar da maioría das linguaxes de programación populares, pero a miúdo son pasadas por alto polos programadores PHP. Linguaxes como Ruby son extremadamente pesadas en Excepcións, polo que sempre que algo vai mal como unha petición HTTP fallando, ou unha consulta de BD vai mal, ou mesmo se un recurso de imaxe non se puido atopar, Ruby (ou as xemas sendo usadas) lanzarán unha excepción á pantalla significando que instantaneamente sabes que hai un erro.

PHP en si é bastante laxo con isto, e unha chamada a file_get_contents() xeralmente só che dará un FALSE e unha advertencia. Moitos frameworks PHP antigos como CodeIgniter só retornarán un false, rexistrarán unha mensaxe nos seus rexistros propietarios e quizais te deixen usar un método como $this->upload->get_error() para ver que foi mal. O problema aquí é que tes que ir buscando un erro e verificar a documentación para ver cal é o método de erro para esta clase, en lugar de tero feito extremadamente obvio.

Outro problema é cando as clases automaticamente lanzan un erro á pantalla e saen do proceso. Cando fas isto paras outro desenvolvedor de poder manexar dinamicamente ese erro. As excepcións deberían ser lanzadas para facer un desenvolvedor consciente dun erro; entón poden elixir como manexar isto. Ex.:

<?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)
{
    // A validación fallou
}
catch(Fuel\Email\SendingFailedException $e)
{
    // O driver non puido enviar o email
}
finally
{
    // Executado independentemente de se unha excepción foi lanzada, e antes de que a execución normal continúe
}

Excepcións SPL

A clase xenérica Exception proporciona moi pouco contexto de depuración para o desenvolvedor; con todo, para remediar isto, é posible crear un tipo de Exception especializado sub-clasificando a clase xenérica Exception:

<?php
class ValidationException extends Exception {}

Isto significa que podes engadir múltiples bloques catch e manexar diferentes Excepcións de forma diferente. Isto pode levar á creación de moitas Excepcións personalizadas, algunhas das cales poderían ser evitadas usando as Excepcións SPL proporcionadas na extensión SPL.

Se por exemplo usas o Método Máxico __call() e un método inválido é solicitado entón en lugar de lanzar unha Excepción estándar que é vaga, ou crear unha Excepción personalizada só para iso, poderías simplemente throw new BadMethodCallException;.

Back to Top

Seguridade

O mellor recurso que atopei sobre seguridade PHP é The 2018 Guide to Building Secure PHP Software por Paragon Initiative.

Seguridade de Aplicacións Web

É moi importante para cada desenvolvedor PHP aprender os básicos da seguridade de aplicacións web, que se poden dividir en unha mancheada de temas amplos:

  1. Separación código-datos.
    • Cando os datos son executados como código, obtés Inxección SQL, Cross-Site Scripting, Inclusión Local/Remota de Arquivos, etc.
    • Cando o código é impreso como datos, obtés filtrado de información (divulgación de código fonte ou, no caso de programas C, información suficiente para evitar ASLR).
  2. Lóxica da aplicación.
    • Controles de autenticación ou autorización faltantes.
    • Validación de entrada.
  3. Ambiente operativo.
    • Versións de PHP.
    • librarías de terceiros.
    • O sistema operativo.
  4. Debilidades de criptografía.

Hai xente mala lista e disposta a explotar a túa aplicación web. É importante que tomes as precaucións necesarias para endurecer a seguridade da túa aplicación web. Afortunadamente, a boa xente de The Open Web Application Security Project (OWASP) compilou unha lista completa de problemas de seguridade coñecidos e métodos para protexerte contra eles. Isto é unha lectura obrigatoria para o desenvolvedor consciente da seguridade. Survive The Deep End: PHP Security por Padraic Brady é tamén outra boa guía de seguridade de aplicacións web para PHP.

Hash de Contrasinais

Eventualmente todos constrúen unha aplicación PHP que depende do login de usuario. Os nomes de usuario e contrasinais son almacenados nunha base de datos e máis tarde usados para autenticar usuarios ao facer login.

É importante que haxees correctamente os contrasinais antes de almacenalos. Haxear e encriptar son dúas cousas moi diferentes que a miúdo se confunden.

Haxear é unha función irreversible e unidireccional. Isto produce unha cadea de lonxitude fixa que non pode ser factiblemente revertida. Isto significa que podes comparar un hash contra outro para determinar se ambos veñen da mesma cadea fonte, pero non podes determinar a cadea orixinal. Se os contrasinais non están haxeados e a túa base de datos é accedida por un terceiro non autorizado, todas as contas de usuario están agora comprometidas.

A diferenza do haxear, a encriptación é reversible (sempre que teñas a chave). A encriptación é útil noutras áreas, pero é unha pobre estratexia para almacenar contrasinais de forma segura.

Os contrasinais tamén deberían ser individualmente salados engadindo unha cadea aleatoria a cada contrasinal antes de haxear. Isto prevén ataques de dicionario e o uso de “táboas arco da vella” (unha lista inversa de hashes criptográficos para contrasinais comúns).

Haxear e salar son vitais xa que a miúdo os usuarios usan o mesmo contrasinal para múltiples servizos e a calidade do contrasinal pode ser pobre.

Ademais, deberías usar un algoritmo especializado de hash de contrasinal en lugar dunha función de hash criptográfico rápida e de propósito xeral (ex. SHA256). A lista curta de algoritmos aceptábeis de hash de contrasinal (a partir de xuño de 2018) para usar son:

Afortunadamente, hoxe en día PHP fai isto fácil.

Haxear contrasinais con password_hash

En PHP 5.5 password_hash() foi introducido. Neste momento está usando BCrypt, o algoritmo máis forte actualmente soportado por PHP. Será actualizado no futuro para soportar máis algoritmos segundo sexa necesario. A libraría password_compat foi creada para proporcionar compatibilidade cara adiante para PHP >= 5.3.7.

Abaixo haxeamos unha cadea, e entón verificamos o hash contra unha nova cadea. Porque as nosas dúas cadeas fonte 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)) {
    // Contrasinal Correcto
} else {
    // Contrasinal incorrecto
}

password_hash() coida do salado de contrasinais para ti. O sal está almacenado, xunto co algoritmo e “custo”, como parte do hash. password_verify() extrae isto para determinar como verificar o contrasinal, polo que non necesitas un campo separado de base de datos para almacenar os teus sales.

Filtrado de Datos

Nunca (nunca) confíes na entrada estraña introducida no teu código PHP. Sempre sanitiza e valida a entrada estraña antes de usala no código. As funcións filter_var() e filter_input() poden sanitizar texto e validar formatos de texto (ex. enderezos de email).

A entrada estraña pode ser calquera cousa: datos de entrada de formulario $_GET e $_POST, algúns valores no superglobal $_SERVER, e o corpo da petición HTTP vía fopen('php://input', 'r'). Lembra, a entrada estraña non está limitada a datos de formulario enviados polo usuario. Arquivos subidos e descargados, valores de sesión, datos de cookies, e datos de servizos web de terceiros son entrada estraña tamén.

Mentres os datos estraños poden ser almacenados, combinados, e accedidos máis tarde, aínda é entrada estraña. Cada vez que procesas, saes, concatenas, ou inclúes datos no teu código, pregúntate se os datos están filtrados adecuadamente e se poden ser confiábeis.

Os datos poden ser filtrados diferentemente baseado no seu propósito. Por exemplo, cando a entrada estraña non filtrada é pasada á saída da páxina HTML, pode executar HTML e JavaScript no teu sitio! Isto é coñecido como Cross-Site Scripting (XSS) e pode ser un ataque moi perigoso. Unha forma de evitar XSS é sanitizar todos os datos xerados polo usuario antes de saílos á túa páxina eliminando etiquetas HTML coa función strip_tags() ou escapando caracteres con significado especial ás súas respectivas entidades HTML coas funcións htmlentities() ou htmlspecialchars().

Outro exemplo é pasar opcións para ser executadas na liña de comandos. Isto pode ser extremadamente perigoso (e xeralmente é unha mala idea), pero podes usar a función integrada escapeshellarg() para sanitizar os argumentos do comando executado.

Un último exemplo é aceptar entrada estraña para determinar un arquivo para cargar desde o sistema de arquivos. Isto pode ser explotado cambiando o nome do arquivo a unha ruta de arquivo. Necesitas eliminar "/", "../", bytes nulos, ou outros caracteres da ruta do arquivo para que non poida cargar arquivos ocultos, non públicos, ou sensíbeis.

Sanitización

A sanitización elimina (ou escapa) caracteres ilegais ou inseguros da entrada estraña.

Por exemplo, deberías sanitizar a entrada estraña antes de incluír a entrada no HTML ou inserila nunha consulta SQL bruta. Cando usas parámetros vinculados con PDO, sanitizará a entrada para ti.

Ás veces é requirido permitir algunhas etiquetas HTML seguras na entrada cando a inclúes na páxina HTML. Isto é moi difícil de facer e moitos evítano usando outro formato máis restritivo como Markdown ou BBCode, aínda que librarías de lista branca como HTML Purifier existen por esta razón.

Ver Filtros de Sanitización

Deserialización

É perigoso unserialize() datos de usuarios ou outras fontes non confiábeis. Facelo pode permitir a usuarios maliciosos instanciar obxectos (con propiedades definidas polo usuario) cuxos destructores serán executados, mesmo se os obxectos en si non son usados. Polo tanto deberías evitar deserializar datos non confiábeis.

Usa un formato seguro e estándar de intercambio de datos como JSON (vía json_decode e json_encode) se necesitas pasar datos serializados ao usuario.

Validación

A validación asegura que a entrada estraña é o que esperas. Por exemplo, podes querer validar un enderezo de email, un número de teléfono, ou idade cando procesas un envío de rexistro.

Ver Filtros de Validación

Arquivos de Configuración

Cando creas arquivos de configuración para as túas aplicacións, as mellores prácticas recomiendan que un dos seguintes métodos sexa seguido:

Register Globals

NOTA: A partir de PHP 5.4.0 a configuración register_globals foi eliminada e xa non pode ser usada. Isto só está incluído como unha advertencia para calquera no proceso de actualizar unha aplicación legada.

Cando está habilitada, a configuración register_globals fai dispoñíbeis varios tipos de variables (incluíndo as de $_POST, $_GET e $_REQUEST) no ámbito global da túa aplicación. Isto pode facilmente levar a problemas de seguridade xa que a túa aplicación non pode efectivamente dicir de onde veñen os datos.

Por exemplo: $_GET['foo'] estaría dispoñíbel vía $foo, que pode sobrescribir variables que foron declaradas.

Se estás usando PHP < 5.4.0 asegúrate de que register_globals está desactivado.

Reporte de Erros

O rexistro de erros pode ser útil para atopar os puntos problemáticos na túa aplicación, pero tamén pode expoñer información sobre a estrutura da túa aplicación ao mundo exterior. Para protexer efectivamente a túa aplicación de problemas que poderían ser causados pola saída destas mensaxes, necesitas configurar o teu servidor diferentemente en desenvolvemento versus produción (en vivo).

Desenvolvemento

Para mostrar cada erro posible durante o desenvolvemento, configura as seguintes configuracións no teu php.ini:

display_errors = On
display_startup_errors = On
error_reporting = -1
log_errors = On

Pasar o valor -1 mostrará cada erro posible, mesmo cando novos niveis e constantes son engadidos en futuras versións de PHP. A constante E_ALL tamén se comporta deste xeito a partir de PHP 5.4. - php.net

A constante de nivel de erro E_STRICT foi introducida en 5.3.0 e non é parte de E_ALL, con todo converteuse en parte de E_ALL en 5.4.0. Que significa isto? En termos de reportar cada erro posible na versión 5.3 significa que debes usar ou -1 ou E_ALL | E_STRICT.

Reportando cada erro posible por versión de PHP

Produción

Para ocultar erros no teu ambiente de produción, configura o teu php.ini como:

display_errors = Off
display_startup_errors = Off
error_reporting = E_ALL
log_errors = On

Con estas configuracións en produción, os erros aínda serán rexistrados nos rexistros de erro do servidor web, pero non serán mostrados ao usuario. Para máis información sobre estas configuracións, vexa o manual de PHP:

Back to Top

Probas

Escribir probas automatizadas para o teu código PHP é considerado unha boa práctica e pode levar a aplicacións ben construídas. As probas automatizadas son unha gran ferramenta para asegurar que a túa aplicación non se rompe cando estás facendo cambios ou engadindo nova funcionalidade e non deberían ser ignoradas.

Hai varios tipos diferentes de ferramentas de probas (ou frameworks) dispoñibles para PHP, que usan diferentes enfoques - todos os cales están tentando evitar as probas manuais e a necesidade de grandes equipos de Garantía de Calidade, só para asegurar que os cambios recentes non romperon a funcionalidade existente.

Desenvolvemento Dirixido por Probas

Desde Wikipedia:

O desenvolvemento dirixido por probas (TDD) é un proceso de desenvolvemento de software que depende da repetición dun ciclo de desenvolvemento moi curto: primeiro o desenvolvedor escribe un caso de proba automatizado que falla que define unha mellora desexada ou nova función, entón produce código para pasar esa proba e finalmente refactoriza o novo código a estándares aceptábeis. Kent Beck, a quen se lle acredita ter desenvolvido ou ‘redescubrido’ a técnica, declarou en 2003 que TDD fomenta deseños simples e inspira confianza.

Hai varios tipos diferentes de probas que podes facer para a túa aplicación:

Probas Unitarias

As Probas Unitarias son un enfoque de programación para asegurar que funcións, clases e métodos están funcionando como esperado, desde o punto en que os constrúes todo o camiño a través do ciclo de desenvolvemento. Ao verificar valores que entran e saen de varias funcións e métodos, podes asegurar que a lóxica interna está funcionando correctamente. Ao usar Inxección de Dependencias e construír clases “mock” e stubs podes verificar que as dependencias son usadas correctamente para unha mellor cobertura de probas.

Cando creas unha clase ou función deberías crear unha proba unitaria para cada comportamento que debe ter. A un nivel moi básico deberías asegurar que dá erro se lle envías argumentos malos e asegurar que funciona se lle envías argumentos válidos. Isto axudará a asegurar que cando fagas cambios a esta clase ou función máis tarde no ciclo de desenvolvemento que a funcionalidade antiga continúa funcionando como esperado. A única alternativa a isto sería var_dump() nun test.php, que non é forma de construír unha aplicación - grande ou pequena.

O outro uso para as probas unitarias é contribuír ao código aberto. Se podes escribir unha proba que mostre funcionalidade rota (é dicir, falla), entón arranxala, e mostra a proba pasando, os parches son moito máis propensos a ser aceptados. Se executas un proxecto que acepta pull requests entón deberías suxerir isto como un requisito.

PHPUnit é o framework de probas de facto para escribir probas unitarias para aplicacións PHP, pero hai varias alternativas:

Probas de Integración

Desde Wikipedia:

As probas de integración (ás veces chamadas Integración e Proba, abreviado “I&T”) é a fase na proba de software na cal módulos individuais de software son combinados e probados como un grupo. Ocorre despois das probas unitarias e antes das probas de validación. As probas de integración toman como entrada módulos que foron probados unitariamente, agrúpanos en agregados máis grandes, aplican probas definidas nun plan de proba de integración a eses agregados, e entregan como saída o sistema integrado listo para probas de sistema.

Moitas das mesmas ferramentas que poden ser usadas para probas unitarias poden ser usadas para probas de integración xa que moitos dos mesmos principios son usados.

Probas Funcionais

Ás veces tamén coñecidas como probas de aceptación, as probas funcionais consisten en usar ferramentas para crear probas automatizadas que realmente usan a túa aplicación en lugar de só verificar que unidades individuais de código están comportándose correctamente e que unidades individuais poden falar entre si correctamente. Estas ferramentas tipicamente traballan usando datos reais e simulando usuarios reais da aplicación.

Ferramentas de Proba Funcional

Desenvolvemento Dirixido por Comportamento

Hai dous tipos diferentes de Desenvolvemento Dirixido por Comportamento (BDD): SpecBDD e StoryBDD. SpecBDD enfócase no comportamento técnico do código, mentres que StoryBDD enfócase en comportamentos ou interaccións de negocio ou funcionalidades. PHP ten frameworks para ambos tipos de BDD.

Con StoryBDD, escribes historias lexíbeis por humanos que describen o comportamento da túa aplicación. Estas historias poden entón ser executadas como probas reais contra a túa aplicación. O framework usado en aplicacións PHP para StoryBDD é Behat, que está inspirado no proxecto Cucumber de Ruby e implementa o DSL Gherkin para describir o comportamento das funcionalidades.

Con SpecBDD, escribes especificacións que describen como o teu código real debería comportarse. En lugar de probar unha función ou método, estás describindo como esa función ou método debería comportarse. PHP ofrece o framework PHPSpec para este propósito. Este framework está inspirado no proxecto RSpec para Ruby.

Enlaces BDD

Ferramentas de Proba Complementarias

Ademais dos frameworks individuais de proba e comportamento dirixido, tamén hai un número de frameworks xenéricos e librarías auxiliares útiles para calquera enfoque preferido tomado.

Enlaces de Ferramentas

Back to Top

Servidores e Despregue

As aplicacións PHP poden ser desplegadas e executadas en servidores web de produción de varias formas.

Plataforma como Servizo (PaaS)

PaaS proporciona a arquitectura de sistema e rede necesaria para executar aplicacións PHP na web. Isto significa pouco ou ningún configuración para lanzar aplicacións PHP ou frameworks PHP.

Recentemente PaaS converteuse nun método popular para desplegar, hospedar e escalar aplicacións PHP de todos os tamaños. Podes atopar unha lista de proveedores PHP PaaS “Plataforma como Servizo” na nosa sección de recursos.

Servidores Virtuais ou Dedicados

Se estás cómodo coa administración de sistemas, ou estás interesado en aprendela, os servidores virtuais ou dedicados danche control completo do ambiente de produción da túa aplicación.

nginx e PHP-FPM

PHP, vía o Xestor de Procesos FastCGI integrado de PHP (FPM), combina realmente ben con nginx, que é un servidor web lixeiro e de alto rendemento. Usa menos memoria que Apache e pode manexar mellor máis peticións concurrentes. Isto é especialmente importante en servidores virtuais que non teñen moita memoria de sobra.

Apache e PHP

PHP e Apache teñen unha longa historia xuntos. Apache é tremendamente configurábel e ten moitos módulos dispoñíbeis para estender a funcionalidade. É unha elección popular para servidores compartidos e unha configuración fácil para frameworks PHP e aplicacións de código aberto como WordPress. Desafortunadamente, Apache usa máis recursos que nginx por defecto e non pode manexar tantos visitantes ao mesmo tempo.

Apache ten varias configuracións posibles para executar PHP. A máis común e fácil de configurar é o [MPM prefork] con mod_php. Aínda que non é o máis eficiente en memoria, é o máis simple para facer funcionar e usar. Isto é probablemente a mellor elección se non queres profundizar demasiado nos aspectos de administración do servidor. Nota que se usas mod_php DEBES usar o MPM prefork.

Alternativamente, se queres exprimir máis rendemento e estabilidade de Apache entón podes aproveitar o mesmo sistema FPM que nginx e executar o [MPM worker] ou [MPM event] con mod_fastcgi ou mod_fcgid. Esta configuración será significativamente máis eficiente en memoria e moito máis rápida pero é máis traballo para configurar.

Se estás executando Apache 2.4 ou máis recente, podes usar mod_proxy_fcgi para obter gran rendemento que é fácil de configurar.

Servidores Compartidos

PHP ten servidores compartidos para agradecer a súa popularidade. É difícil atopar un host sen PHP instalado, pero asegúrate de que é a versión máis recente. Os servidores compartidos permiten que ti e outros desenvolvedores despleguen sitios web a unha única máquina. O lado positivo disto é que se converteu nunha mercadoría barata. O lado negativo é que nunca sabes que tipo de alboroto os teus veciños inquilinos van crear; cargar o servidor ou abrir buratos de seguridade son as principais preocupacións. Se o orzamento do teu proxecto pode permitirse evitar servidores compartidos, deberías.

Asegúrate de que os teus servidores compartidos están ofrecendo as versións máis recentes de PHP.

Construíndo e Desplegando a túa Aplicación

Se te atopas facendo cambios manuais no esquema da base de datos ou executando as túas probas manualmente antes de actualizar os teus arquivos (manual), pensa dúas veces! Con cada tarefa manual adicional necesaria para desplegar unha nova versión da túa aplicación, as posibilidades de erros potencialmente fatais aumentan. Sexa que estés lidando cunha actualización simple, un proceso de construción completo ou mesmo unha estratexia de integración continua, a automatización de construción é a túa amiga.

Entre as tarefas que podes querer automatizar están:

Ferramentas de Despliegue

As ferramentas de despliegue poden ser descritas como unha colección de scripts que manexan tarefas comúns do despliegue de software. A ferramenta de despliegue non é parte do teu software, actúa no teu software desde ‘fóra’.

Hai moitas ferramentas de código aberto dispoñíbeis para axudarte coa automatización de construción e despliegue, algunhas están escritas en PHP outras non. Isto non debería impedirte usalas, se están mellor axustadas para o traballo específico. Aquí hai algúns exemplos:

Phing pode controlar o teu proceso de empaquetado, despliegue ou proba desde dentro dun arquivo de construción XML. Phing (que está baseado en Apache Ant) proporciona un rico conxunto de tarefas xeralmente necesarias para instalar ou actualizar unha aplicación web e pode ser estendido con tarefas personalizadas adicionais, escritas en PHP. É unha ferramenta sólida e robusta e existe desde hai moito tempo, con todo a ferramenta podería ser percibida como un pouco antiga debido á forma en que trata coa configuración (arquivos XML).

Capistrano é un sistema para programadores intermedios-a-avanzados para executar comandos dunha forma estruturada e repetíbel nunha ou máis máquinas remotas. Está pre-configurado para desplegar aplicacións Ruby on Rails, con todo podes desplegar exitosamente sistemas PHP con el. O uso exitoso de Capistrano depende dun coñecemento funcional de Ruby e Rake.

Ansistrano é un par de roles de Ansible para xestionar facilmente o proceso de despliegue (desplegar e reverter) para aplicacións de script como PHP, Python e Ruby. É un port de Ansible para Capistrano. Xa foi usado por moitas empresas PHP.

Deployer é unha ferramenta de despliegue escrita en PHP. É simple e funcional. As funcionalidades inclúen executar tarefas en paralelo, despliegue atómico e manter consistencia entre servidores. Recetas de tarefas comúns para Symfony, Laravel, Zend Framework e Yii están dispoñíbeis. O artigo de Younes Rafie Despliegue Fácil de Aplicacións PHP con Deployer é un gran tutorial para desplegar a túa aplicación coa ferramenta.

Magallanes é outra ferramenta escrita en PHP con configuración simple feita en arquivos YAML. Ten soporte para múltiples servidores e ambientes, despliegue atómico, e ten algunhas tarefas integradas que podes aproveitar para ferramentas e frameworks comúns.

Lectura adicional:

Provisión de Servidores

Xestionar e configurar servidores pode ser unha tarefa desalentadora cando te enfrontas a moitos servidores. Hai ferramentas para lidar con isto para que poidas automatizar a túa infraestrutura para asegurar que tes os servidores correctos e que están configurados adecuadamente. A miúdo integranse cos maiores provedores de hosting na nube (Amazon Web Services, Heroku, DigitalOcean, etc) para xestionar instancias, o que fai que escalar unha aplicación sexa moito máis fácil.

Ansible é unha ferramenta que xestiona a túa infraestrutura a través de arquivos YAML. É simple para comezar e pode xestionar aplicacións complexas e de gran escala. Hai unha API para xestionar instancias na nube e pode xestionalas a través dun inventario dinámico usando certas ferramentas.

Puppet é unha ferramenta que ten a súa propia linguaxe e tipos de arquivo para xestionar servidores e configuracións. Pode ser usado nunha configuración mestre/cliente ou pode ser usado nun modo “sen mestre”. No modo mestre/cliente os clientes consultarán o(s) mestre(s) central(es) para nova configuración en intervalos establecidos e actualizaranse se é necesario. No modo sen mestre podes empuxar cambios aos teus nodos.

Chef é un poderoso framework de integración de sistemas baseado en Ruby co que podes construír todo teu ambiente de servidor ou caixas virtuais. Integrase ben con Amazon Web Services a través do seu servizo chamado OpsWorks.

Lectura adicional:

Integración Continua

A Integración Continua é unha práctica de desenvolvemento de software onde os membros dun equipo integran o seu traballo frecuentemente, xeralmente cada persoa integra polo menos diariamente — levando a múltiples integracións por día. Moitos equipos atopan que este enfoque leva a problemas de integración significativamente reducidos e permite a un equipo desenvolver software cohesivo máis rapidamente.

– Martin Fowler

Hai diferentes formas de implementar integración continua para PHP. Travis CI fixo un gran traballo de facer a integración continua unha realidade mesmo para proxectos pequenos. Travis CI é un servizo de integración continua hospedado. Pode ser integrado con GitHub e ofrece soporte para moitas linguaxes incluíndo PHP. GitHub ten fluxos de traballo de integración continua con GitHub Actions.

Lectura adicional:

Back to Top

Virtualización

Executar a túa aplicación en diferentes ambientes en desenvolvemento e produción pode levar a estraños bugs aparecendo cando vas en vivo. Tamén é complicado manter diferentes ambientes de desenvolvemento actualizados coa mesma versión para todas as librarías usadas cando traballas cun equipo de desenvolvedores.

Se estás a desenvolver en Windows e desplegando en Linux (ou calquera cousa non-Windows) ou estás a desenvolver nun equipo, deberías considerar usar unha máquina virtual. Isto soa complicado, pero ademais dos ambientes de virtualización amplamente coñecidos como VMware ou VirtualBox, hai ferramentas adicionais que poden axudarte a configurar un ambiente virtual en uns poucos pasos fáceis.

Vagrant

Vagrant axúdache a construír as túas caixas virtuais sobre os ambientes virtuais coñecidos e configurará estes ambientes baseado nun único arquivo de configuración. Estas caixas poden ser configuradas manualmente, ou podes usar software de “provisión” como Puppet ou Chef para facelo por ti. Provisionar a caixa base é unha gran forma de asegurar que múltiples caixas están configuradas dunha forma idéntica e elimina a necesidade de que mantengas listas complicadas de comandos de “configuración”. Tamén podes “destruír” a túa caixa base e recreala sen moitos pasos manuais, facendo fácil crear unha instalación “fresca”.

Vagrant crea carpetas para compartir o teu código entre o teu host e a túa máquina virtual, o que significa que podes crear e editar os teus arquivos na túa máquina host e entón executar o código dentro da túa máquina virtual.

Docker

Docker - unha alternativa lixeira a unha máquina virtual completa - é chamado así porque é todo sobre “contenedores”. Un contenedor é un bloque de construción que, no caso máis simple, fai un traballo específico, ex. executar un servidor web. Unha “imaxe” é o paquete que usas para construír o contenedor - Docker ten un repositorio cheo deles.

Unha aplicación LAMP típica podería ter tres contenedores: un servidor web, un proceso PHP-FPM e MySQL. Como con carpetas compartidas en Vagrant, podes deixar os teus arquivos de aplicación onde están e dicirlle a Docker onde atopalos.

Podes xerar contenedores desde a liña de comandos (vex exemplo abaixo) ou, para facilidade de mantemento, construír un arquivo docker-compose.yml para o teu proxecto especificando cales crear e como se comunican entre si.

Docker pode axudar se estás desenvolvendo múltiples sitios web e queres a separación que vén de instalar cada un na súa propia máquina virtual, pero non tes o espazo de disco necesario ou o tempo para manter todo actualizado. É eficiente: a instalación e descargas son máis rápidas, só necesitas almacenar unha copia de cada imaxe por moito que sexa usada, os contenedores necesitan menos RAM e comparten o mesmo kernel do SO, polo que podes ter máis servidores executándose simultaneamente, e leva cuestión de segundos para parar e iniciar os, non hai necesidade de esperar por un arranque completo do servidor.

Exemplo: Executando as túas Aplicacións PHP en Docker

Despois de instalar docker na túa máquina, podes iniciar un servidor web cun comando. O seguinte descargará unha instalación Apache completamente funcional coa versión máis recente de PHP, mapeará /path/to/your/php/files ao directorio raíz do documento, que podes 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

Isto inicializará e lanzará o teu contenedor. -d fáilo executar en segundo plano. Para paralo e iniciarlo, simplemente executa docker stop my-php-webserver e docker start my-php-webserver (os outros parámetros non son necesarios de novo).

Aprender máis sobre Docker

O comando anterior mostra unha forma rápida de executar un servidor básico. Hai moito máis que podes facer (e miles de imaxes pre-construídas no Docker Hub). Toma tempo para aprender a terminoloxía e ler a Guía de Usuario de Docker para obter o máximo dela, e non executes código aleatorio que descargaches sen verificar que é seguro – as imaxes non oficiais poden non ter os últimos parches de seguridade. Se dubidas, mantente nos repositorios oficiais.

O sitio PHPDocker.io xerará automaticamente todos os arquivos que necesitas para un stack LAMP/LEMP completamente funcional, incluíndo a túa elección de versión de PHP e extensións.

Back to Top

Caché

PHP é bastante rápido por si mesmo, pero os cuellos de botella poden xurdir cando fas conexións remotas, cargas arquivos, etc. Afortunadamente, hai varias ferramentas dispoñibles para acelerar certas partes da túa aplicación, ou reducir o número de veces que estas varias tarefas que consumen tempo necesitan executarse.

Caché de Opcode

Cando un arquivo PHP é executado, debe primeiro ser compilado en opcodes (instrucións de linguaxe de máquina para a CPU). Se o código fonte non cambiou, os opcodes serán os mesmos, polo que este paso de compilación convértese nun desperdicio de recursos da CPU.

Un caché de opcode prevén a compilación redundante almacenando opcodes en memoria e reutilizándoos en chamadas sucesivas. Tipicamente verificará a sinatura ou tempo de modificación do arquivo primeiro, no caso de que houbese cambios.

É probable que un caché de opcode faga unha mellora significativa de velocidade na túa aplicación. Desde PHP 5.5 hai un integrado - Zend OPcache. Dependendo do teu paquete/distribución de PHP, xeralmente está activado por defecto - verifica opcache.enable e a saída de phpinfo() para asegurar. Para versións anteriores hai unha extensión PECL.

Ler máis sobre cachés de opcode:

Caché de Obxectos

Hai veces cando pode ser beneficioso cachear obxectos individuais no teu código, como con datos que son custosos de obter ou chamadas de base de datos onde o resultado é improbable que cambie. Podes usar software de caché de obxectos para manter estas pezas de datos en memoria para acceso extremadamente rápido máis tarde. Se gardas estes elementos nun almacén de datos despois de recuperalos, entón tíralos directamente do caché para peticións seguintes, podes obter unha mellora significativa no rendemento así como reducir a carga nos teus servidores de base de datos.

Moitas das solucións populares de caché de bytecode permiten que cachees datos personalizados tamén, polo que hai aínda máis razón para aproveitar delas. APCu e WinCache ambos proporcionan APIs para gardar datos do teu código PHP ao seu caché de memoria.

Os sistemas de caché de obxectos en memoria máis comunmente usados son APCu e memcached. APCu é unha excelente elección para caché de obxectos, inclúe unha API simple para engadir os teus propios datos ao seu caché de memoria e é moi fácil de configurar e usar. A única limitación real de APCu é que está vinculado ao servidor no que está instalado. Memcached por outra banda está instalado como un servizo separado e pode ser accedido a través da rede, significando que podes almacenar obxectos nun almacén de datos hiper-rápido nunha localización central e moitos sistemas diferentes poden tirar del.

Nota que se o caché é compartido a través de procesos PHP depende de como PHP é usado. Cando executas PHP vía PHP-FPM, o caché é compartido a través de todos os procesos de todos os pools. Cando executas PHP como unha aplicación (Fast-)CGI dentro do teu servidor web, o caché non é compartido, é dicir cada proceso PHP terá os seus propios datos APCu. Cando executas PHP na liña de comandos, o caché non é compartido e só existirá durante a duración do comando, polo que tes que ser consciente da túa situación e obxectivos. Podes querer considerar usar memcached en cambio, xa que non está vinculado aos procesos PHP.

Nunha configuración en rede APCu xeralmente superará memcached en termos de velocidade de acceso, pero memcached será capaz de escalar máis rápido e máis lonxe. Se non esperas ter múltiples servidores executando a túa aplicación, ou non necesitas as funcionalidades extra que memcached ofrece entón APCu é probablemente a túa mellor elección para caché de obxectos.

Exemplo de lóxica usando APCu:

<?php
// verifica se hai datos gardados como 'expensive_data' no caché
$data = apcu_fetch('expensive_data');
if ($data === false) {
    // os datos non están no caché; garda o resultado da chamada custosa para uso posterior
    apcu_add('expensive_data', $data = get_expensive_data());
}

print_r($data);

Aprender máis sobre sistemas populares de caché de obxectos:

Back to Top

Documentando o teu Código

PHPDoc

PHPDoc é un estándar informal para comentar código PHP. Hai moitos tags diferentes dispoñíbeis. A lista completa de tags e exemplos pode ser atopada no [manual de PHPDoc].

Abaixo hai un exemplo de como poderías documentar unha clase con algúns métodos;

<?php
/**
 * @author A Name <a.name@example.com>
 * @link https://docs.phpdoc.org/
 */
class DateTimeHelper
{
    /**
     * @param mixed $anything Calquera cousa que poidamos converter a un obxecto \DateTime
     *
     * @throws \InvalidArgumentException
     *
     * @return \DateTime
     */
    public function dateTimeFromAnything($anything)
    {
        $type = gettype($anything);

        switch ($type) {
            // Algún código que tenta retornar un obxecto \DateTime
        }

        throw new \InvalidArgumentException(
            "Failed Converting param of type '{$type}' to DateTime object"
        );
    }

    /**
     * @param mixed $date Calquera cousa que poidamos converter a un obxecto \DateTime
     *
     * @return void
     */
    public function printISO8601Date($date)
    {
        echo $this->dateTimeFromAnything($date)->format('c');
    }

    /**
     * @param mixed $date Calquera cousa que poidamos converter a un obxecto \DateTime
     */
    public function printRFC2822Date($date)
    {
        echo $this->dateTimeFromAnything($date)->format('r');
    }
}

A documentación para a clase como un todo ten a tag @author e unha tag @link. A tag @author é usada para documentar o autor do código e pode ser repetida para documentar varios autores. A tag @link é usada para enlazar a un sitio web indicando unha relación entre o sitio web e o código.

Dentro da clase, o primeiro método ten unha tag @param documentando o tipo, nome e descrición do parámetro que está sendo pasado ao método. Ademais ten as tags @return e @throws para documentar o tipo de retorno, e calquera excepción que podería ser lanzada respectivamente.

O segundo e terceiro métodos son moi similares e teñen unha única tag @param como tiña o primeiro método. A diferenza importante entre o bloque de documentación do segundo e terceiro métodos é a inclusión/exclusión da tag @return. @return void informa explicitamente que non hai retorno; historicamente omitir a declaración @return void tamén resulta na mesma acción (sen retorno).

Back to Top

Recursos

Desde a fonte

Xente para seguir

É difícil atopar membros da comunidade PHP interesantes e coñecedores cando estás a comezar. Podes atopar unha lista abreviada de membros da comunidade PHP para comezar en:

Provedores PHP PaaS

Frameworks

En lugar de reinventar a roda, moitos desenvolvedores de PHP empregan frameworks para crear aplicacións web. Os frameworks abstraen moitas das preocupacións de baixo nivel e proporcionan interfaces útiles e fáciles de usar para completar tarefas comúns.

Non é necesario usar un framework para cada proxecto. Ás veces, o PHP simple é o camiño correcto, pero se necesitas un framework, hai tres tipos principais dispoñibles:

Os microframeworks son esencialmente un envoltorio para enrutar unha solicitude HTTP a unha devolución de chamada, controlador, método, etc. o máis rápido posible, e ás veces veñen con algunhas bibliotecas adicionais para axudar ao desenvolvemento, como envoltorios básicos de bases de datos e similares. Úsanse de xeito destacado para crear servizos HTTP remotos.

Moitos frameworks engaden un número considerable de funcións ademais do que está dispoñible nun microframework; estes chámanse frameworks de pila completa. A miúdo inclúen ORM, paquetes de autenticación, etc.

Os marcos baseados en compoñentes son coleccións de bibliotecas especializadas e de propósito único. Os marcos baseados en compoñentes dispares pódense usar xuntos para crear un marco de micropila ou de pila completa.

Compoñentes

Como se mencionou anteriormente, os “compoñentes” son outra maneira de abordar o obxectivo común de crear, distribuír e implementar código compartido. Existen varios repositorios de compoñentes, dos cales os dous principais son:

Ambos repositorios teñen ferramentas de liña de comandos asociadas para axudar nos procesos de instalación e actualización, e foron explicados con máis detalle na sección xestión de dependencias.Dependency Management

Tamén existen marcos de traballo baseados en compoñentes e provedores de compoñentes que non ofrecen ningún marco de traballo. Estes proxectos proporcionan outra fonte de paquetes que idealmente teñen poucas ou ningunha dependencia doutros paquetes ou marcos de traballo específicos.

Por exemplo, podes usar o paquete FuelPHP Validation, sen necesidade de usar o propio framework FuelPHP.

As compoñentes Laravel’s Illuminate components estará mellor desacoplado do framework de Laravel. Por agora, só os compoñentes mellor desacoplados do framework de Laravel están listados arriba.

Outros recursos útiles

Follas de referencia - Cheatsheets

Mellores boas prácticas

Novidades nas comunidades de PHP e desenvolvemento web

Podes subscribirte a boletíns semanais para manterte informado sobre novas bibliotecas, últimas novas, eventos e anuncios xerais, así como sobre recursos adicionais que se publican de cando en vez:

Tamén hai semanarios noutras plataformas que che poden interesar; aquí tes unha lista dalgunhas.

Universo PHP

Titoriais en vídeo

Canles YouTube

Vídeos de pago

Libros

Hai moitos libros sobre PHP; por desgraza, algúns xa son bastante antigos e xa non son precisos. En particular, evita os libros sobre “PHP 6”, unha versión que xa nunca existirá. A seguinte gran versión de PHP despois da 5.6 foi “PHP 7”, en parte por isto.

Esta sección pretende ser un documento dinámico para libros recomendados sobre desenvolvemento en PHP en xeral. Se queres que se engada o teu libro, envía unha solicitude de resposta e será revisado para comprobar a súa relevancia.

Libros Gratuitos

Libros de pago

Back to Top

Comunidade

A comunidade PHP é tan diversa como grande, e os seus membros están preparados e dispostos a apoiar aos novos programadores de PHP. Considera unirte ao teu grupo de usuarios de PHP local (PUG) ou asistir a conferencias PHP máis grandes para aprender máis sobre as mellores prácticas que se mostran aquí. Podes pasar o tempo no IRC na canle #phpc en irc.libera.chat e seguir o @phpc, en Discord, en X ou en Mastodon. Sae á rúa, coñece novos desenvolvedores, aprende novos temas e, sobre todo, crea novos amigos! Outros recursos comunitarios inclúen StackOverflow.

Lee o calendario oficial de eventos PHP

PHP Grupos de usuarios

Se vives nunha cidade grande, é probable que haxa un grupo de usuarios de PHP preto. Podes atopar facilmente o teu PUG local en PHP.ug. As fontes alternativas poderían ser Meetup.com ou unha busca por php user group near me usando o teu motor de busca favorito (i.e. Google). Se vives nunha vila pequena, pode que non haxa un PUG local; se é o caso, crea un!

Cómpre facer unha mención especial a dous grupos de usuarios a nivel mundial: NomadPHP and PHPWomen. NomadPHP ofrece reunións de grupos de usuarios en liña dúas veces ao mes con presentacións dalgúns dos mellores relatores da comunidade PHP. PHPWomen é un grupo de usuarios non exclusivo dirixido orixinalmente ás mulleres do mundo PHP. A adhesión está aberta a todas as persoas que apoien unha comunidade máis diversa. PHPWomen proporciona unha rede de apoio, mentoría e educación e en xeral promove a creación dunha atmosfera profesional e “amigable para as mulleres”.

Lea sobre os grupos de usuarios na Wiki de PHP

Conferencias PHP

A comunidade PHP tamén alberga conferencias regionais e nacionais en moitas países ao redor do mundo. Membros dunha reputación dunha comunidade PHP usualmente fala nestes eventos maiores, polo que é unha gran oportunidade para aprender directamente de líderes dunha industria.

Atopar unha conferencia PHP

ElePHPants

ElePHPant é esa fermosa mascota do proxecto PHP cun elefante no seu deseño. Foi deseñada orixinalmente para o proxecto PHP en 1998 por Vincent Pontier - pai espiritual de miles de elePHPants en todo o mundo, e dez anos despois tamén naceron uns adorables elefantes de peluche. Agora, os elePHPants están presentes en moitas conferencias de PHP e con moitos desenvolvedores de PHP nos seus ordenadores para divertirse e inspirarse.

Entrevista con Vincent Pontier