Criando Extensões para o PHP: Parte II – Configuração do Ambiente de Desenvolvimento no Windows

Olá Amigos!

Este é o segundo post da nossa série “Criando Extensões para o PHP“, até agora este foi o post que mais exigiu pesquisa e dedicação, trabalhei para que ele ficasse o mais enxuto possível e também irei descrever os erros de configuração e as respectivas respostas que tive ao longo do caminho. Antes de mais nada você precisa se certificar que está com o PHP instalado e funcionando. Em um post anterior eu sugeri um tutorial de instalação da mesma versão que estamos utilizando aqui, a 5.4.4, fique a vontade para atualizar. Acidentalmente durante a pesquisa para este trabalho encontrei outro tutorial de instalação mais completo e descrevendo algumas particularidades, vale a pena dar uma olhada.

Em nosso segundo post da série que aborda o desenvolvimento de extensões para o PHP (se você não viu o primeiro clique aqui) iremos configurar o ambiente de desenvolvimento no Windows e por fim obteremos nossa extensão na forma de uma DLL. Antes que os mais detalhistas digam que mencionei no post passado que trabalharíamos com extensões build-in eu acrescento que ao longo da pesquisa me deparei com este tipo de abordagem e acreditei ser mais válida a abordagem neste primeiro momento, já que sua implementação é mais simples.

Inicialmente pensei em utilizar o NetBeans como IDE, no entanto percebi que absolutamente ninguém o utilizava, e interessado em saber o porque descobri a lista de compiladores suportados pelo PHP no ambiente Windows, e ainda descobri que o compilador MinGW, que eu pretendia utilizar juntamente com o NetBeans é explicitamente não suportado. E assim levando em conta este fato com tom engraçado descobri ainda que a recomendação é utilizar o Microsoft Visual C++ para “buildar” o PHP no Windows, eu na minha eterna ingenuidade não havia (incrivelmente) ligado os pontos, já que vamos compilar o PHP para rodar em um produto Microsoft, nada melhor que utilizar um compilador Microsoft.

Bom, dadas as cartas na mesa, vamos ver o que iremos precisar neste momento:

.

1. Instalações e Configuração de Arquivos e Diretórios

Após ter em mãos todos os arquivos, instale:

  1. Microsoft Visual C++ 2008 Express Edition (pode ir tomar m café, demora um pouco).
  2. Microsoft Windows SDK for Windows 7 and .NET Framework.
  3. Crie uma pasta no C:/ denominada “php-dev”.
  4. Descompacte o arquivo de fontes do PHP para dentro do “php-dev” de maneira que os fontes fiquem acessíveis como: “C:/php-dev/php-5.4.4”
  5. Descompacte nossas bibliotecas Win32 Build Tools para dentro da pasta “php-dev”, de maneira que fique: “C:/php-dev/win32build”
  6. Copie o arquivo “bison.exe” de dentro de “C:/php-dev/win32build/bin” para “C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin”
.

1. Preparando o Ambiente de Desenvolvimento

No menu iniciar, abra o “Microsoft Visual Studio 2008 Command Prompt“. Vá até a pasta do código fonte do PHP, no nosso exemplo fica:

cd C:/php-dev/php-5.4.4

Agora vamos executar dos scripts, o buildconf.bat e configure.js. Esta etapa é importante pois vai criar alguns arquivos que serão incluídos em nosso projeto e resolver este erro no momento do Build:

Compiling...
stdafx.cpp
C:php-devphp-5.4.4-srcZendzend_config.w32.h(25) : fatal error C1083: Cannot open include file: '../main/config.w32.h': No such file or directory

Quando estava escrevendo este post tive o problema abaixo no momento da execução de ambos, veja:

c:php-devphp-5.4.4>buildconf.bat
Erro de entrada: Não há mecanismo de script para a extensão de arquivo ".js".
Now run 'configure --help'

c:php-devphp-5.4.4>cscript/nologo configure.js
Erro de entrada: Não há mecanismo de script para a extensão de arquivo ".js".

Estou desenvolvendo este trabalho Windows 7 64 bits, acho que este é um problema comum da versão, para resolver veja este tutorial (em inglês), bem simples, é só seguir os passos. Após seguir os passos do tutorial, tente executar os scripts novamente.

Caso tudo der certo você terá uma tela semelhante a da figura abaixo. Após o último comando o script configure vai gerar uma resposta enorme, a imagem abaixo contém apenas o começo dela.

Início do retorno após a execução do script configure.js

2. Configuração da IDE com o Código Fonte do PHP

Abra o Microsoft Visual Studio C++ 2008 Express Edition, crie um novo projeto Win32 (File -> New -> Project -> Win32 ->Win32 Project), dê um nome a ele, em nosso exemplo “php_first_extension”. Em seguida irá abrir uma janela: “Win32 Application Wizard – php_first_extension”, clique em “Next”. Na próxima tela do assistente você terá um grupo de opções denominado “Application Type“, selecione “DLL“. e por fim clique em “Finish”. Quando você terminar terá uma estrutura no “Solution Explorer” como na figura abaixo:

Solution Explorer – Microsoft Visual C++ 2008 Express Edition

Muito bem! Agora temos que configurar algumas diretivas nas propriedades projeto. Clique com  o botão direito sobre o nome do projeto (php_first_extension), e no fim da lista vá em “Properties“. Abrirá uma janela “php_frist_extension Property Pages”, e dentro dela você irá ver a sua esquerda vários itens filhos de “Configuration Priperties“, dentre os itens, os que vão nos interessar são: “General“, “C/C++” e “Linker“. Não vou entrar em detalhes sobre cada um, apenas altere as configurações de acordo com o que está sem seguida.

Entre no subitem “General“, altere as seguintes configurações:

  • “Character Set” para “Use Multi-byte Character Set”.
Em seguida, entre no subitem C/C++, em “General” e altere as seguintes diretivas:
  • “Debug Information Format” para “Program Database (/ZI)”.
  • “Detect 64-bit Portability Issues” para “No” (Se você estiver no Windows 64, como é no meu caso, esta opção já deve aparecer como “No”).
  • “Addition Include Directories”, neste campo você irá indicar onde os fontes do PHP estão, conforme você baixou e descompactou no Item 1 (“C:/php-dev/php-5.4.4”), após a configuração irá ficar desta maneira:
C:/php-dev/php-5.4.4/main 
C:/php-dev/php-5.4.4/Zend 
C:/php-dev/php-5.4.4/TSRM 
C:/php-dev/php-5.4.4/
.
Em seguida no subitem Preprocessor, adicione em Preprocessor Definitions:
ZEND_DEBUG=0    
ZTS=1    
ZEND_WIN32
PHP_WIN32
Feito isso, vamos para o subitem seguinte “Code Generation“, sete as configurações como está abaixo:
  • “Enable String Pooling” para “Yes (/GF)”.
  • “Enable Minimal Rebuild” para “No”.
  • “Basic Runtime Checks” para “Default”.
  • “Runtime Library” para “Multi-threaded Debung (/MTd)”.
.
No próximo item da lista, “Linker“, no primeiro subitem “General”, mude a seguinte configuração: “Adition Library Directories“, adicionando o caminho “C:/php/dev”, que é onde meu PHP está instalando e funcionando, veja não é o diretório dos fontes do PHP, se você olhar dentro deste diretório verá o arquivo “php5ts.lib“, que no subitem “Input”, procure pela propriedade “Addition Dependencies“, e coloque “php5ts.lib“.
.
Ok, até agora nenhuma tarefa complicada (apensar de muito extensa), já estamos com nossas ferramentas instaladas e configuras. No item seguinte vamos criar um pequeno exemplo.
.

3. Exemplo de Extensão e Configuração com o PHP

Agora que temos nosso projeto criado, e o ambiente de desenvolvimento configurado vamos criar um pequeno exemplo, e “junta-lo” com nosso PHP já instalado.

Primeiramente abra o arquivo de cabeçalho stdafx.h, que está em “Header Files”, apague todo seu conteúdo e coloque:

#ifdef PHP_WIN32
   #pragma once
   #include "zend_config.w32.h"
   #include "php.h"
#endif

Em seguida, abra o arquivo php_first_extension.cpp, apague todo seu conteúdo e coloque:

#include "stdafx.h"

PHP_FUNCTION(first_extension);

zend_function_entry php_fist_extension_functions[] = {
   PHP_FE(first_extension, NULL)
   {NULL, NULL, NULL}
};

PHP_MINIT_FUNCTION(php_first_extension)
{
   return SUCCESS;
}

PHP_MINFO_FUNCTION(php_first_extension)
{
}

zend_module_entry php_first_extension_module_entry = {
   STANDARD_MODULE_HEADER,
   "PHP First Extension do Blog do Tiago",
   php_fist_extension_functions,
   PHP_MINIT(php_first_extension),
   NULL, 
   NULL, 
   NULL, 
   PHP_MINFO(php_first_extension),
   "0.1", 
   STANDARD_MODULE_PROPERTIES
};

ZEND_GET_MODULE(php_first_extension)

PHP_FUNCTION(first_extension)
{
   char *strMensagemSucesso = "Parabéns! sua extensão está funcionando!";
   RETURN_STRING(strMensagemSucesso, 1);
}

Remova do projeto os outros arquivos, não vamos utiliza-los por enquanto. Quando ao código no próximo post explico mais profundamente sobre ele.

Bom, agora vamos construir nosso projeto. Mais uma vez com o botão direito sobre o nosso do nosso projeto, clique em Build, ele irá começar a compilar nosso código, que resultará em um arquivo chamado “php_first_extension.dll” que estará dentro da pasta “Debug” no caminho que você salvou o projeto no seu computador. Você verá uma mensagem parecida como esta na IDE:

1>------ Build started: Project: php_first_extension, Configuration: Debug Win32 ------
1>Linking...
1>   Creating library C:UsersTiagoDocumentsVisual Studio 2008Projectsphp_first_extensionDebugphp_first_extension.lib and object C:UsersTiagoDocumentsVisual Studio 2008Projectsphp_first_extensionDebugphp_first_extension.exp
1>Embedding manifest...
1>Build log was saved at "file://c:UsersTiagoDocumentsVisual Studio 2008Projectsphp_first_extensionphp_first_extensionDebugBuildLog.htm"
1>php_first_extension - 0 error(s), 0 warning(s)
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

Para testar este exemplo de extensão, copie o arquivo “php_first_extension.dll” para o diretório “ext“, no meu caso “C:/php-5.4.4/ext”, em seguida abra o arquivo php.ini (que está um diretório acima), procure pelas linhas onde estão o “loading” das extenções, e então adicione:

extension=php_first_extesion.dll

Feche o arquivo php.ini salvando as alterações, restarte seu servidor web (se estiver utilizando o Apache, pode-se utilizar o “Apache System Monitor”).

Crie um arquivo PHP no diretório acessível do seu servidor, dê o nome que quiser, neste arquivo vamos chamar nossa extensão com o seguinte código:

<?php
    echo first_extension();
?>

Se tudo correr bem você verá a seguinte mensagem na tela: “Parabéns! sua extensão está funcionando!“. Se você criar um arquivo PHP com a função “php_info()”, nele você também irá notar os dados da sua extensão, vale a pena ver!

Se você quiser pode fazer o download dos arquivos do projeto aqui.

4. Conclusão da Segunda Parte

Nesta segunda parte fizemos o download das ferramentas necessárias para a construção de extensões no Microsoft Windows, instalamos e as configuramos, além de elaborar e “testar” um pequeno exemplo de extensão externa (dll). A tarefa foi simples, nos próximos posts vamos explorar um pouco da Zend API e elaborar projetos mais complexos.

Referencias

.

Abraços,

Tiago.

Vídeo Aulas: Criando um Mini-Framework MVC com PHP

Olá amigos!

Esses dias eu estava navegando e encontrei algumas vídeo aulas do Mateus Moura, achei bem interessante a abordagem e a construção. Nestas que listei abaixo ele constrói do zero um framework MVC utilizando PHP. Apensar de se contra a construção de frameworks caseiros, acredito que quem nunca trabalhou dessa maneira,  ao ver essas vídeo aulas poderá entender melhor quando iniciar seu aprendizado, como por exemplo, da Zend Framework.

Listei as vídeo aulas abaixo com os respectivos assuntos, espero que seja útil.

  1. Parte I: Arquivo .htaccess, URL amigáveis e estrutura de diretórios.
  2. Parte II: Explorando os Models
  3. Parte III: Melhorando o Framework, tratamento de erros, captura de parâmetros na URL
  4. Parte IV: Helpers e início da construção de um exemplo
  5. Parte V: Construção de um Exemplo (boa exploração dos controllers e models)
  6. Parte VI: Exploração mais profunda dos Helpers
  7. Parte VII:Helpers, inicializadores, Login, Administração do Site
  8. Parte VIII: Explicações e esclarecimento de dúvidas (Complemento da Aula 7)
  9. Parte IX: Explicações gerais sobre os conceitos apresentados.

 

Abraços,

Tiago.

Criando Extensões para o PHP: Parte I – Introdução

Olá Leitores!

Hoje pretendo iniciar uma empreitada ao “submundo” do PHP, onde vamos explorar suas entranhas e tentar escrever uma extensão. Apesar desse tema parecer ir na contra-mão das tendencias (leia-se Frameworks), tem-se que em determinadas situações, isso para não dizer bem específicas, é necessário escrever suas funções diretamente em C/C++.

Já devo ter lido em algum lugar (não me lembro onde) que se caso você tenha uma função que seja muito usada, seria melhor escreve-la em C. Provavelmente a motivação de quem escreveu (e também a minha) é o ganho computacional que se tem, uma vez que o os códigos C/C++ são muito mais rápidos em comparação com os escritos em PHP.

Antes de iniciar a pesquisa para este post eu me deparei com uma dificuldade em especial: Falta de material de referencia, quando não ausente, está desatualizado. No manual do PHP que fala sobre este tema encontra-se algo, mas referente ao PHP 4, de acordo com uma viso logo no início. Mas como estamos apenas fazendo um experimento, vamos trabalhar com oque temos e no decorrer da série de posts, veremos o que acontece.

Antes de mais nada, consideremos alguns fatores como premissas:

  • A abordagem será direta, dando o caminho das pedras do “como fazer”.
  • Compreender a fundo o funcionamento interno do PHP é difícil, então vamos nos ater ao que interessa.
  • O estudo pode ser árduo, então vamos praticar, tentar e retentar. A palavra chave vai ser transpiração.
  • Você deve conhecer um pouco de C/C++? Mais a frente ele será necessário. Pretendo escrever sobre este assunto aqui no blog, em paralelo.

Para contextualizar e entender o que estamos nos propondo a fazer vamos dar uma olhadas nas possibilidades que temos, dada a arquitetura de funcionamento do PHP. Os itens adiante descrevem de acordo com o manual oficial as possibilidades de extensão da linguagem e alguns casos que já foram implementados.

1. PHP, o que é e como Funciona

O PHP é descrito como uma linguagem, e é por definição uma linguagem interpretada, e assim ela possui um interpretador, denominado Zend Engine, que é uma espécie de máquina virtual, assim como no Java (só que mais rápido). Sendo que um dos motivos que popularizou o PHP é justamente a capacidade de estender o seu interpretador! A função do interpretador (que também iremos chamar de núcleo ou core) é ler o código fonte e “traduzi-lo” em código executável – linguagem de máquina. O núcleo do PHP está escrito em C, e para estende-lo iremos utilizar o C++ (poderíamos utilizar o C, mas por razões que você verá durante a série será mais conveniente utilizar C++).

Bom, agora sabemos que o PHP possui um núcleo chamado Zend Engine que é responsável por compilar e executar nossos scripts, só que o PHP em si é um pouco maior do que isso (bem maior na verdade), e está divido em três partes:

  • Interprete: Zend Engine, que faz o trabalho que descrevemos acima, se você quiser se aprofundar veja aqui e aqui.
  • Funcionalidade: implementa as funções da linguagem, as que você já deve conhecer.
  • Interface: Faz a interface com o servidor Web (e. g. Apache).

Na figura abaixo temos a a exemplificação da arquitetura do PHP, juntando os itens que citamos anteriormente:

Arquitetura Interna de Funcionamento do PHP
Fonte: Manual do PHP

Na figura você pode notar que todo acesso a banco de dados é feito pelos módulos, que são extensões do núcleo, e onde justamente nossa extensão vai estar. Ainda observando a figura tem-se o trajeto de ida e volta no paradigma cliente-servidor, onde a aplicação é solicitada no servidor web (1), por meio da interface (2) o Zend Engine é chamado, e em seguida irá buscar o script no disco do servidor (3), que será compilado e executado (4), nesse meio tempo o interpretador poderá acessar um dado módulo que é chamado no script, e após será compilado e executado (4). A resposta é enviada de volta a interface do servidor (5), que por sua vez enviará de volta ao navegador (6).

Agora sabemos que nosso ambiente de trabalho poderá estar em três seções, vejamos então quais são as possibilidades.

1.1 Extensões Externas

As funções externas são aquelas que pode ser carregadas externamente pela função dl(), tem-se que estes são casos muito específicos, pois dadas as desvantagens deste método o ganho de desempenho proposto no início do post não faz sentido, uma vez que estes carregamentos demandam muita memória (e tempo!). Dê uma olhada na tabela abaixo retirada do manual do PHP:

Vantagens Desvantagens
Os módulos externos não necessitam que você recompile o PHP. É necessário carregar a extensão todas as vezes que for usa-la.
O tamanho do PHP não é alterado. É necessário fazer acesso ao disco (o que é muito lento) toda vez que o módulo for requisitado.

O manual ainda cita que este é um método que pode ser usado caso você esteja em um ambiente compartilhado, o que é mais comum na maioria dos casos, pois não há possibilidade de recompilar o PHP com a extensão, ou modificar alguma diretiva no arquivo php.ini.

1.2 Build-in Modules

Como você já deve ter percebido esta é a abordagem que nos interessa: vamos desenvolver um módulo e compila-lo junto com o PHP, acredito que seja neste contexto que teremos o ganho de desempenho mais considerável. Uma das reflexões que podemos ter nesta abordagem é: Posso ter minha aplicação totalmente feita e compilada junto com PHP? Separei dois itens abaixo onde temos um parenteses sobre esta reflexão e outra que irá complementar o item 1.3, estes subitens não estão muito direcionados na nossa empreitada, no entanto que vale a pena ler.

Abaixo tem-se a tabela com as vantagens e desvantagens dessa abordagem, o conteúdo também foi adaptado do manual do PHP.

Vantagens Desvantagens
Não é necessário carregar explicitamente o módulo, ele apresenta-se como uma funcionalidade nativa do PHP. Necessita de recompilar o PHP.
Não existem arquivos externos a serem carregados. Tudo já está compilado junto com o PHP. O PHP cresce e consumirá mais memória.

Uma das desvantagens citadas é o aumento no consumo de memória. Não podemos esquecer que a boa programação do nosso módulo vai minimizar este efeito, e que seus malefícios também poderiam ser percebidos se a nossa extensão fosse implementada em código PHP; pense como exemplo a manipulação de imagens, no decorrer da nossa aboragem vamos analisar, como estudo de caso, o material do post do Francismo de Souza Júnior, onde ele desenvolve uma extensão para detecção de objetos utilizando a biblioteca OpenCV.

Uma das considerações mais obvias que temos é que nesta abordagem é necessário que, caso pretenda utilizar seu módulo como nativo no PHP, você tem há de dispor de um servidor onde possa modificar o PHP a seu gosto, como uma hospedagem dedicada, dado que vamos recompilar o PHP.

1.2.1 Algumas palavras sobre as modificações do Facebook, o HipHop

Em fevereiro de 2010 a equipe de desenvolvimento do PHP postou em seu blog uma novidade, o denomindado HipHop, que na verdade não é uma extensão, mas sim um PHP totalmente modificado, onde inicialmente tinha-se que ele realiza a transformação do código PHP em para C++, que por sua vez era compilado pelo g++. Dê uma olhada na figura abaixo para observar o processo:

Transformação de código PHP em executável.
Fonte: Br-Linux

De acordo com o post, a preocupação inicial era com o desempenho (consumo de CPU) das linguagens interpretadas frente as compiladas. No decorrer da narrativa o autor cita o desenvolvimento de extensões e argumenta que dado o tamanho da equipe e a complexidade que envolvia o desenvolvimento das tais extensões, transcrever as regras de negócio do Facebook inicialente escritas em PHP para código C++ seria um trabalho demasiado custoso, tendo em vista os aspectos como o conhecimento de C++ e da Zend API (nos aprofundaremos neste tópico nos próximos posts), por fim é citado que obteve-se um ganho de 50% na execução da aplicação.

Este é um assunto que cabe um post mais específico para investigar o assunto, pretendo em breve escrever algo sobre.

1.2.2 “Compilando” meu código PHP

De maneira mais simplória do que no HipHop, durante a pequisa para iniciar este post encontrei um post muito interessante no blog do Rafael Clares, que tratava a compilação de classes escritas em PHP em códigos C++ utilizando o módulo nativo do PHP, o bcompiler. Se você pensa em justamente compilar toda sua aplicação, creio que  leitura do Rafael seja mais adequada.

1.3 Modificações no Zend Engine

Nossa terceira e ultima abordagem trata-se da modificação do Zend Engine. Como vimos o núcleo do PHP é responsável por compilar e executar o script em tempo de execução, então pode-se inferir que a modificação do interpretador apenas se justifica quando é necessário modificar o comportamento da linguagem. No manual é evidente que tais modificações não são recomendadas, pois resultariam em incompatibilidades e dada a característica da modificação, aumenta-se o acoplamento da aplicação (o que é um fator indesejado), e para dificultar ainda mais a implementação da extensão, não existe abordagem oficial no manual do PHP para tal. Lembrando que assim como no item 1.2 é necessário recompilar o PHP.

2. Conclusão da Primeira Parte

Bom amigos, chegamos a conclusão da primeira parte do nosso trabalho, agora já sabemos quais são as possibilidades para escrever extensões e citamos alguns exemplos de trabalhos parecidos. No próximo post vamos explorar a anatomia da extensão e configurar o ambiente de desenvolvimento, ainda não decidi se iremos explorar no Linux ou no Windows, estou inclinado a seguir no Windows porque notei alguns trabalhos já explorando o desenvolvimento no Linux, então algo novo seria mais apropriado.

Estou aberto a sugestões, críticas, elogios e qualquer outro tipo de contato! Até o próximo post!

3. Referencias

Abraços,

Tiago.