Back-End

29 ago, 2017

Zephir: escrevendo extensões para PHP

Publicidade

Escrever extensões para PHP nunca foi tão fácil

A linguagem PHP é usada hoje em dia em diversas aplicações e sites por toda a internet. É de longe a linguagem mais usada no server side, chegando a ser responsável por mais de 80% das páginas web.

Como você deve saber, o PHP é escrito em C (Assim como Python e Ruby). Além disso, você pode adicionar recursos e funções à linguagem escrevendo extensões em C e compilando-as junto ao interpretador ou como uma biblioteca dinâmica. Drivers de banco de dados, bibliotecas para manipulação do DOM, frameworks fullstacks (Phalcon) e até mesmo algumas funcionalidades do core da linguagem foram escritas como extensões (como a SPL). Você também tem várias e várias extensões disponíveis através do PECL (PHP Extension Community Library).

Repositório oficial da linguagem PHP: https://github.com/php/php-src
Repositório oficial da linguagem PHP: https://github.com/php/php-src

Talvez você se pergunte “porque diabos eu escreveria uma extensão para a linguagem ?” e bem, embora na maioria das vezes provavelmente não seja necessário, há alguns motivos que levam os desenvolvedores a escreverem extensões para PHP:

  • Drivers: Os exemplos mais triviais são drivers para bancos de dados como MySQL e MongoDB. Embora alguns drivers não sejam providos como extensões, esse tipo de aplicação pode tirar grande vantagem em desempenho quando são compiladas. Por falar em desempenho…
  • Desempenho: É fato que o PHP a partir da versão 7+ vêm se tornando cada vez melhor em desempenho. Contudo, suas aplicações escritas em PHP sempre terão o overhead do interpretador e muito provavelmente um código escrito em PHP não vai executar mais rapidamente que o mesmo código escrito em C.

 

Ok. Escrever drivers para bancos de dados, bibliotecas de manipulação de imagens, entre outras coisas e aproveitar todo o desempenho que C pode oferecer para isso parece tentador, mas há sempre o outro lado da moeda…

  • Desenvolvimento : Escrever, testar, depurar e manter programas em linguagens compiladas e com tipagem estática como C e C++ é geralmente mais complicado do que fazer a mesma coisa com linguagens interpretadas e com tipagem dinâmica como PHP, Javascript ou Python. Isso acaba dificultando o desenvolvimento de novas extensões, principalmente para quem teve pouco ou nenhum contato com C.
  • Zend Engine API: A documentação não ajuda muito. Assim fica meio complicado desenvolver extensões para PHP.

 

E é aí que entra a Zephir…

Have you met Zephir?

Zephir é uma linguagem de programação de alto nível que permite criar extensões compiladas como bibliotecas dinâmicas para a linguagem PHP. Ela une o melhor de dois mundos: A produtividade advinda da flexibilidade de uma linguagem interpretada e tipagem dinâmica com o desempenho compatível com linguagens compiladas e tipagem estática.

Zephir

Um programa escrito em Zephir gera como produto código C que por sua vez é compilado como uma biblioteca dinâmica e a partir daí pode ser usado no PHP. Uma vez compilada, você pode distribuir essa biblioteca onde quer que queira usar, basta registrar em “php.ini” e ser feliz.

Modelo de compilação da Zephir. Imagem extraída de https://docs.zephir-lang.com/en/latest/motivation.html#compilation-vs-interpretation
Modelo de compilação da Zephir. Imagem extraída de https://docs.zephir-lang.com/en/latest/motivation.html#compilation-vs-interpretation

Instalação

Informações detalhadas sobre a instalação da Zephir podem ser encontradas em:

Zephir

Informações adicionais podem ser encontradas junto ao repositório da Zephir no Github:

Zephir

Zephir: principais características

Zephir tem algumas características que a tornam bastante interessante.

  • Tipagem dinâmica / estática: Zephir consegue tirar vantagem tanto da tipagem dinâmica quanto da tipagem estática. Você consegue no mesmo script usar os dois modos de tipagem sem problemas.

 

int a;
var b;
let a = 0; // Permitido
let b = 0; // Permitido
let b = "Hello"; // Permitido
let a = "Hello"; // Erro ! Declaramos 'a' como inteiro anteriormente

 

  • Memory Safe: Zephir foi pensada para ser memory safe, então você não tem variáveis do tipo ponteiro como temos em C. É um detalhe a menos para se preocupar, mas a primeira vista pode parecer estranho para quem lida com ponteiros frequentemente.
  • Multiplataforma: Você pode compilar seu código Zephir / C para bibliotecas dinâmicas em várias plataformas. Arquivos ‘.so’ para Linux/OSX e DLLs para Windows.
  • Built-In methods: Zephir prioriza a programação orientada a objetos, logo não é de se estranhar que alguns arrays e strings sejam tratadas como objetos, assim como alguns tipos primitivos como char e integer. Você pode ver uma lista dos métodos disponíveis aqui.
  • Integração nativa com PHP: Já desenvolve com PHP ? Então você vai se sentir bem à vontade com a Zephir. Na verdade você tem acesso à todas as funções, classes e métodos que tem no PHP. Se um recurso existe no PHP, é certo que você consiga acessá-lo a partir da Zephir.
  • Integração com código/bibliotecas C: Com Zephir, você não fica limitado ao que o PHP também já oferece. Se você já tem um código ou biblioteca escrita em C, pode adicioná-la ao processo de compilação e usar as funções definidas lá.

 

Há, claro alguns outros recursos interessantes como parâmetros somente de leitura (read-only parameters), e a possibilidade de fazer require em seus arquivos PHP diretamente.

Além disso, Zephir nada deve para as linguagens modernas. Tem suporte a closures e namespaces, além de outros recursos comuns em qualquer linguagem de programação moderna.

Zephir: sintaxe

A sintaxe da Zephir não foge muito do “C-style”, logo temos ‘switch’, ‘while’, ‘if’, e ‘break’ da mesma maneira que em C ou PHP. Operações de atribuição devem ser precedidas pela palavra-reservada ‘let’.

O detalhe fica por conta do ‘for’ que na Zephir é usado exclusivamente para percorrer arrays ou strings. Aliás, falando em arrays, você pode usá-los exatamente como faz no PHP com a diferença de que se usa “:” ao invés de “=>” para atribuir valor à uma chave:

array data;
let data = [
 "a": 1,
 "b": 4,
 3: "c",
 "x": [
 "Outro array"
 ]
];
var key, value;
for key, value in data {
 // Faça alguma coisa usando as chaves e os valores
}
for key, _ in data {
 // Faça alguma coisa usando somente as chaves e ignorando os valores
}
for value in data {
 // Faça alguma coisa usando somente os valores
}
for value in reverse data {
 // Faça alguma coisa usando somente os valores percorrendo o array em ordem reversa
}

Além disso, qualquer variável deve ser declarada (com tipo ou não) antes de poder ser usada. Logo, as variáveis que receberão os valores a cada iteração sobre o array devem ser declaradas previamente.

Para quem vem do PHP, o suporte à orientação à objetos é exatamente igual ao que temos lá: Temos interfaces, classes e classes abstratas, níveis de visibilidade são os nossos já conhecidos protected, private e public, além de constantes. Veja só esta classe de exemplo.

namespace Extension\Foo;
use Extension\Bar\AnotherClass;
/**
 * Example class
 */
class Example {
const EXAMPLE_CONST = "Hello, Zephir";
/**
 * Atributo protected sem tipo definido
 */
 protected a {
 get, set // Getter e Setter definidos
 }
/**
 * Atributo protected com tipo definido
 */
 private string a {
 get, set // Getter e Setter definidos
 }
public function __construct() {
 // Familiar, não ?
 }
public function __clone() {
 // Os demais métodos mágicos também estão disponíveis
 }
// Método estático
 public static function staticMethod() -> int | boolean {
 // Este methodo deve retornar um inteiro ou um booleano
 }
public function exampleMethodA(array options) -> string {
 // Este método deve retornar uma string
 }
private function exampleMethodB(int value, string name = "name") -> boolean {
 // Este método deve retornar um valor booleano
 }
// Este metodo recebe uma variavel sem tipo definido e um booleano
 protected function exampleMethodC(anyType, boolean ) -> <AnotherClass> {
 // Este método deve retornar um objeto da classe AnotherClass
 }
// Método sem tipo de retorno definido
 public function exampleMethodC() {
 return function () {
 echo "Hello, closures !";
 }
 }
}

Zephir também facilita a criação dos getters e setters para as variáveis. A menos que você tenha alguma lógica nesses métodos, vale a pena usar a construção acima.

Zephir: CLI

Ao instalar Zephir em seu computador você tem acesso à interface de linha de comando da Zephir.

Zephir CLI: praticidade na hora de trabalhar suas extensões
Zephir CLI: praticidade na hora de trabalhar suas extensões

A partir dessa interface, você consegue criar projetos, exportar seu código Zephir para C, gerar stubs ( converte seus arquivos Zephir para arquivos PHP com classes e métodos definidos, sem as implementações ), e fazer build da sua extensão.

Ao fazer build da extensão, o Zephir vai automáticamente instalar a extensão em seu sistema operacional, assim você já poderá testá-la de imediato em sua instalação do PHP.

Zephir: compilação e otimização

Zephir oferece um conjunto de configurações para compilação e otimização do código resultante. Vale a pena dar uma lida, já que são várias opções e cada uma tem uma finalidade.

Zephir

Zephir

Essas configurações são definidas em um arquivo JSON na raiz do projeto da sua extensão. Vale a pena dar uma olhada com carinho nele.

Arquivo config.json de uma extensão
Arquivo config.json de uma extensão

Zephir: resumo da obra e minhas impressões

Zephir é uma linguagem fácil de aprender e fácil de desenvolver. Não à toa cada vez é mais comum se achar um repositório no Github fazendo uso dessa linguagem.

Uma dica que deixo é que vale bastante a pena dar uma lida sobre como funciona o PHP internamente. O site oficial da linguagem PHP tem uma seção sobre isso.

Meu xodó sempre foi C++ e PHP logo em seguida. Mas como linguagem de programação, eu admito que Zephir me encantou. Tem uma sintaxe clara, simples e objetiva. Você não precisa de rodeios para chegar onde quer e isso é de se esperar de uma linguagem que também nasceu com foco em produtividade.

Em resumo é isso: Zephir está aí e você pode tirar bastante proveito dela em suas aplicações PHP, inclusive em pontos onde desempenho é crítico, ou em classes de sua aplicação onde a implementação dificilmente mudará, pode valer a pena migrar parte do seu código para Zephir. Além disso, é mais uma forma de ajudar o ecossistema de PHP a crescer e evoluir.

Dúvidas ? Sugestões ? Comente aí!

Grande abraço e até a próxima!