Category Archives: programação

A otimização secreta do PHP 5.4 – PHPCast episódio 6

Podcast PHPCast

Uma otimização introduzida no PHP 5.4 – e que foi pouco divulgada – permite que scripts de PHP que criam muitos objetos da mesma classe economizem memória e rodem mais rápido, desde que todas as variáveis sejam previamente declaradas. Este foi um dos principais assuntos discutidos por Manuel Lemos e Ernani Joppert no sexto episódio do PHPCast.

Eles também comentaram sobre o desafio do Prêmio de Inovação em JavaScript, que está sendo organizado pelo site JSClasses, e que em breve vai oferecer prêmios e reconhecimento para desenvolvedores que contribuem com componentes inovadores escritos em JavaScript.

via A otimização secreta do PHP 5.4 – PHPCast episódio 6.

As 7 Principais Otimizações do PHP 5.4 – PHPCast episódio 7

Podcast PHPCast

O PHP 5.4 inclui sete otimizações que tornaram esta versão mais eficiente; não apenas em termos de rapidez de execução, mas também em termos de uso de memória. Este foi um dos principais assuntos do episódio 25 do podcast em inglês Lately in PHP, que foi comentado por Manuel Lemos e Ernani Joppert aqui no episódio 7 do PHPCast.

Este episódio foi gravado em vídeo e transmitido ao vivo para todo o público graças ao Google Hangouts On Air, que permite que qualquer pessoa possa participar e assistir à gravação de hangouts. Os vídeos são disponibilizados depois no canal do YouTube. Siga a conta do Twitter (@phpclassesearly) para saber quando o próximo episódio vai ser gravado para poder participar também.

via As 7 Principais Otimizações do PHP 5.4 – PHPCast episódio 7.

Qualidade de Software: dicas para escrever um código de qualidade

Em um projeto de software, utilizar rotinas é algo comum e sem ela é praticamente impossível desenvolver um software complexo. Independentemente da arquitetura e utilizando ou não orientação a objeto, as rotinas tem grande importância. A Rotina pode ser um método ou procedimento que são ativados para um único propósito (execução dos nossos desejos em relação ao software). Desenvolver uma rotina de qualquer maneira pode afetar o processamento da aplicação ou então confundir outro colaborador que mais tarde poderá efetuar severas manutenções. Neste artigo demonstrarei os passos necessários para construir um código de qualidade.

Olá a todos! Para escrever este artigo estou sendo guiado por duas grandes obras da área de qualidade de software: CODE COMPLETE de Steve McConnell e CÓDIGO LIMPO de Robert C. Martin. O objetivo do texto é mostrar alguns passos que podem favorecer o desenvolvimento de códigos com qualidades. Este processo irá facilitar manutenção e a vida dos colegas que tiverem que alterar seu código.

Veja este artigo em: Qualidade de Software: dicas para escrever um código de qualidade.

PDO em PHP Orientado a Objetos

Nesse artigo vou mostrar como usar o PDO para conectar em um banco de dados em PHP orientado a objetos.

Nesse exemplo estou usando o banco de dados MySQL.

Vamos primeiramente criar um banco de dados chamado “teste”. Ver Listagem 1

Listagem 1: Código para criar um banco de dados no MySQL query

CREATE DATABASE IF NOT EXISTS teste

Agora vamos criar a estrutura da classe de conexão. Para isso vamos criar um arquivo chamado conexao.php e criar a nossa classe database que será uma abstrata. Ver Listagem 2.

Listagem 2: Estrutura da classe database

<?php
abstract class database{
}
?>

Vamos então adicionar os métodos padrões para as classes abstratas que são o __construct, __clone e __destruct. Ver Listagem 3.

Os métodos __construct e __destruct.são padrões do php e são responsáveis por construir e destruir a instancia da nossa classe.

O método __clone evita que nossa classe seja clonada.

Listagem 3: Classe usuarios com os métodos __construct, __clone e __destruct

<?php
abstract class database{
	/*Método construtor do banco de dados*/
	private function __construct(){}

	/*Evita que a classe seja clonada*/
	private function __clone(){}

	/*Método que destroi a conexão com banco de dados e remove da memória todas as variáveis setadas*/
	public function __destruct() {
		foreach ($this as $key => $value) {
			unset($this->$key);
        }
	}
}
?>

Na listagem 3 o método __destruct remove da memória todas as variáveis que foram setadas pela nossa classe.

Agora vamos criar os métodos de conexão e fechar a conexão com o BD. Ver Listagem 4.

Listagem 4: Métodos connect e disconnect

<?php
abstract class database{
	/*Método construtor do banco de dados*/
	private function __construct(){}

	/*Evita que a classe seja clonada*/
	private function __clone(){}

	/*Método que destroi a conexão com banco de dados e remove da memória todas as variáveis setadas*/
	public function __destruct() {
		$this->disconnect();
		foreach ($this as $key => $value) {
			unset($this->$key);
        }
	}

	private static $dbtype   = "mysql";
	private static $host     = "localhost";
	private static $port     = "3306";
	private static $user     = "root";
	private static $password = "123";
	private static $db       = "teste";

	/*Metodos que trazem o conteudo da variavel desejada
	@return   $xxx = conteudo da variavel solicitada*/
	private function getDBType()  {return self::$dbtype;}
	private function getHost()    {return self::$host;}
	private function getPort()    {return self::$port;}
	private function getUser()    {return self::$user;}
	private function getPassword(){return self::$password;}
	private function getDB()      {return self::$db;}

	private function connect(){
		try
		{
			$this->conexao = new PDO($this->getDBType().":host=".$this->getHost().";port=".$this->getPort().";dbname=".$this->getDB(), $this->getUser(), $this->getPassword());
		}
		catch (PDOException $i)
		{
			//se houver exceção, exibe
			die("Erro: <code>" . $i->getMessage() . "</code>");
		}

		return ($this->conexao);
	}

	private function disconnect(){
		$this->conexao = null;
	}
}
?>

Veja a definição das variáveis privadas usadas para conexão na Listagem 4:

dbtype – define uma string que informa qual a plataforma de banco de dados que estamos usando. Para o MySQL usamos a string “mysql” e para o SQL Server usamos a string “mssql”. Veja nesse link http://br.php.net/manual/en/pdo.drivers.php os drives de banco de dados suportados pelo PDO
host – define o nome do host
port – define a porta do host
user – define o usuário de acesso ao banco de dados
password – define a senha de acesso ao banco de dados
db – define o nome do banco de dados

O método connect tenta se conectar com o banco de dados usando as informações passadas pelas variáveis privadas, caso não consiga retorna um erro.

O método disconnect finaliza a conexão com o banco de dados. Perceba que esse método está sendo chamado pelo método __destruct, ou seja, ele sempre será executado ao término da utilização da classe database.

Por fim vamos criar os métodos insert, select, update e delete para fazer o nosso CRUD. Ver Listagem 5.

Listagem 5: Métodos insert, select, update e delete

<?php
abstract class database{
	/*Método construtor do banco de dados*/
	private function __construct(){}

	/*Evita que a classe seja clonada*/
	private function __clone(){}

	/*Método que destroi a conexão com banco de dados e remove da memória todas as variáveis setadas*/
	public function __destruct() {
		$this->disconnect();
		foreach ($this as $key => $value) {
			unset($this->$key);
        }
	}

	private static $dbtype   = "mysql";
	private static $host     = "localhost";
	private static $port     = "3306";
	private static $user     = "root";
	private static $password = "123";
	private static $db       = "teste";

	/*Metodos que trazem o conteudo da variavel desejada
	@return   $xxx = conteudo da variavel solicitada*/
	private function getDBType()  {return self::$dbtype;}
	private function getHost()    {return self::$host;}
	private function getPort()    {return self::$port;}
	private function getUser()    {return self::$user;}
	private function getPassword(){return self::$password;}
	private function getDB()      {return self::$db;}

	private function connect(){
		try
		{
			$this->conexao = new PDO($this->getDBType().":host=".$this->getHost().";port=".$this->getPort().";dbname=".$this->getDB(), $this->getUser(), $this->getPassword());
		}
		catch (PDOException $i)
		{
			//se houver exceção, exibe
			die("Erro: <code>" . $i->getMessage() . "</code>");
		}

		return ($this->conexao);
	}

	private function disconnect(){
		$this->conexao = null;
	}

	/*Método select que retorna um VO ou um array de objetos*/
	public function selectDB($sql,$params=null,$class=null){
		$query=$this->connect()->prepare($sql);
		$query->execute($params);

		if(isset($class)){
			$rs = $query->fetchAll(PDO::FETCH_CLASS,$class) or die(print_r($query->errorInfo(), true));
		}else{
			$rs = $query->fetchAll(PDO::FETCH_OBJ) or die(print_r($query->errorInfo(), true));
		}
		self::__destruct();
		return $rs;
    }

	/*Método insert que insere valores no banco de dados e retorna o último id inserido*/
	public function insertDB($sql,$params=null){
		$conexao=$this->connect();
		$query=$conexao->prepare($sql);
		$query->execute($params);
		$rs = $conexao->lastInsertId() or die(print_r($query->errorInfo(), true));
		self::__destruct();
		return $rs;
    }

	/*Método update que altera valores do banco de dados e retorna o número de linhas afetadas*/
	public function updateDB($sql,$params=null){
		$query=$this->connect()->prepare($sql);
		$query->execute($params);
		$rs = $query->rowCount() or die(print_r($query->errorInfo(), true));
		self::__destruct();
		return $rs;
    }

	/*Método delete que excluí valores do banco de dados retorna o número de linhas afetadas*/
	public function deleteDB($sql,$params=null){
		$query=$this->connect()->prepare($sql);
		$query->execute($params);
		$rs = $query->rowCount() or die(print_r($query->errorInfo(), true));
		self::__destruct();
		return $rs;
    }
}
?>

Os métodos insert, update e delete tem quase a mesma codificação, eles recebem o comando SQL e e os parâmetros então o executa retornando o número de linhas afetadas. A diferença é que o método insert retorna o último id inserido na tabela.

Caso aconteça algum erro ao tentar executar o comando esses métodos retornam o erro.

O método select recebe o SQL, os parâmetros e o nome de uma classe para o qual o método transformará os dados da tabela em objetos. Para isso é necessário criar uma classe de mapeamento VO (Value Objects) que receberá esses dados.

Caso não seja passado o nome de uma classe ele retorna um array de objetos.

Assim como nos métodos insert, update e delete, se acontecer algum erro o método select retorna esse erro.

Ficamos por aqui, até o próximo artigo.

Fonte: Linha de Código – Artigos

 

Long Polling com #PHP

Olá Pessoal !
Como mostrei a forma de se fazer um Long Polling utilizando Node.JS ( Long Polling com Node.JS ) , irei mostrar agora a forma de se fazer com PHP.

Importante !

Funcionar funciona, apesar de não ser tão eficiente quanto ao long polling feito utilizando node.js, não foram testados os efeitos colaterais no servidor, tais como desempenho e concorrência de uso, afinal estamos utilizando PHP.

A Técnica

Bom, para começar eu gostaria que vocês lessem o post do Long Polling com Node.JS para entender um pouco mais da técnica utilizada, o que na verdade só é uma técnica e aplicando o que foi proposto por ela:

  • Abrir a conexão e não deixar que esta seja fechada sem resposta
  • Se a conexão for fechada por algum motivo, tentar reabrir
  • Não fechar a conexão até ter uma resposta esperada

Vocês irão ter um Long Polling com sucesso, então vamos lá .!

Lógica, Codificação

Criei quatro arquivos { “index.php” , “data.txt” , “server.php” , “client.js” } o data.txt contém os dados que serão mostrados, mas antes disso será feita uma comparação lógica, que se baseia em NÃO emitir uma resposta se : ‘os dados do data.txt estiverem vazios, se o conteúdo do data.txt for igual ao conteúdo requisitado’

Conteúdo requisitado ? quando recebemos uma resposta do servidor, que obviamente só vamos receber se houver conteúdo, nos capturamos o que foi retornado e enviamos por query string de volta ; Por que ? para comparar se o conteúdo atual ou futuro do data.txt é diferente, pois não vamos responder ou perguntar algo que já sabemos, lembrando que a mesma coisa vale para um banco de dados.

Nosso código PHP ficaria assim:

<?php
       while ( true ) {
              $data = file_get_contents ( 'data.txt' ) ;
              $requested = isset ( $_GET [ 'content' ] ) ? $_GET [ 'content' ] : null ;
              if ( strlen ( $data ) > 0 && $requested !== $data ) {
                     echo $data ;
                     break ;
              } else {
                     sleep ( 2 ) ; // vamos dar um intervalo !
                     continue ;
              }
       }

O que fizemos ? iniciamos um loop infinito, logicamente se ele não for parado a requisição nunca vai terminar, a mesma coisa vale pra quando entramos na página que contém esse código ( server.php ) , e então lemos o conteúdo do arquivo, e procuramos pelo índice content na query string , duas comparações simples ( se a quantidade de caracteres de $data for maior que zero e se $requested for diferente de $data que é o conteúdo do text, emitimos a resposta e paramos o loop , nesse caso a requisição é fechada, feito isso o resto é simples.

Agora, o lado do cliente ( jscript ) , basta criar uma função que é responsável por enviar a requisição para ‘server.php’, e quando esta for fechada ( Http Code 200 ) , criamos a requisição novamente .. e assim por diante ( recursividade )

$ ( document ).ready ( function ( ) {
       $ ( '#ready' ).on ( 'click' , function ( ) {
              startPolling = function ( content ) {
                     content === undefined || $ ( '#response' ).html ( content ) ;
                     var qs = { 'content' : content } ;
                     $.get ( 'server.php' , qs , function ( data ) {
                            startPolling ( data ) ;
                     } ) ;
              } ;

              startPolling ( undefined ) ;
       } ) ;
} ) ;

Só precisamos disso .. bem simples e direto , a unica coisa que tem de demais no código acima, é a recursividade, como eu disse que faz parte da técnica, a conexão precisa ser reaberta caso fechada, e ela só é fechada quando temos a resposta esperada , para testar basta criar um arquivo html e colocar o seguinte código

<html>
       <head>
              <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
              <script type="text/javascript" src="client.js"></script>
       </head>
       <body>
              <input type="button" value="ready" id="ready">
              <div id="response"></div>
       </body>
</html>

Isso é tudo .. agora façam seus testes, não apliquem uma técnica dessa pra algo que possa ser resolvido de outra forma, estude outras maneiras e principalmente, avaliem o custo benefício de cada uma delas, o que foi demonstrado acima funciona, você evita ficar enviando requisições ao servidor quando ele está respondendo o que você não quer , me faz lembrar o burro do shrek .

Abraços, e boa sorte !

 

Long Polling com Node.JS

Bem, esse é um assunto muito interessante e bastante discutido, trata-se de aplicações em tempo-real ( comet ) , nesse caso uma conexão aberta com o servidor aguardando respostas. Enquanto não temos HTML5 em todos navegadores, para poder utilizar os WebSockets, temos que utilizar técnicas Comet para desenvolver aplicações em realtime, como podemos fazer isso !? Podemos utilizar a técnica Long Polling !

Long Polling

É uma técnica comet, que permite que a conexão fique aberta, aguardando uma resposta do servidor para esta ser fechada e reaberta novamente, a diferença do AJAX Polling, que fica enviando requisições mesmo o servidor respondendo ‘não tenho nenhuma resposta’ consecutivamente, isso acaba prejudicando a aplicação e criando um excesso de requisições no servidor, observa-se uma long polling em ação com a imagem abaixo 

Na prática, o que é ?

A conexão deve ser sempre aberta, o que não pode acontecer é essa conexão ser fechada, e o cliente não tentar reabri-la, daí não estamos respondendo de volta. Com Node.JS, temos um Daemon ( Disk And Execution Monitor ) , que lida com todas as requisições recebidas e enviadas ou seja o serviço é independente tanto de resposta, quanto de recebimento, nesse caso temos handlers ( manipuladores ) para as requisições feitas, e dessa forma, manipulamos essas requisições, é aí que entra a mágica !

Com Node.JS, guardamos todos os manipuladores em um objeto de manipuladores, para que possam ser utilizados de acordo com as requisições feitas, logo seguinte trecho de código

var http = require ( 'http' ) ; // Módulo HTTP do Node.JS ( Nativo )
var handlers = new Object ( ) ; // Objeto de manipuladores

Dessa forma, ficam acessíveis a todos , a variável ‘handlers’ é global para todo código portanto, não se preocupem muito com o escopo, além do mais para o que vamos utiliza-la, não teremos esse tipo de problema, vamos criar o servidor HTTP (http.createServer)

var http = require ( 'http' ) ; // Módulo HTTP do Node.JS ( Nativo )
var handlers = new Object ( ) ; // Objeto de manipuladores 

var url = require ( 'url' ) ;
var server = http.createServer ( function ( request , response ) { 

       response.send = function ( httpCode , data , contentType ) {
              var $data ;
              if ( data instanceof Object ) {
                     $data = new Buffer ( JSON.stringify ( data ) ) ;
              } else $data = data.toString ( ) ;
              this.writeHead ( parseInt ( httpCode ) , {
                     'Content-Type' : contentType.toString ( ) ,
                     'Content-Length' : $data.length
              } ) ;
              this.end ( $data ) ;
       } ;

       var path = url.parse ( request.url ).pathname.toString ( ) ;
       if ( path !== null || path !== undefined ) {
              if ( path in handlers !== false ) {
                     if ( typeof handlers [ path ] === 'function' ) {
                            handlers [ path ] ( request , response ) ;
                     }
              }
       }
} ).listen ( 8080 , function ( ) {
       console.log ( 'Servidor iniciado !' ) ;
} ) ;

Vamos precisar do modulo ‘url’ para fazer o parser de urls, ou seja as urls de requisição, é necessário o require desse modulo, logo depois, a adição de um método auxiliar para emitir respostas para o cliente, trata-se do método send no objeto response, que emite respostas de acordo com os parâmetros passados, contentTypecomo todos conhecem, o tipo do conteúdo que está sendo enviado, o código http e os dados, logo abaixo o parser do path da url, testando se este não é nulo ou indefinido , e testando também se este path está registrado como um handler, o que esperamos que seja.

Importante !

Os handlers são mapeados de acordo com o path, o que seria esse path ? é exatamente o que estará no lugar de [path] em ‘http://127.0.0.1:8080/[path]‘.
Mas porque o handler é mapeado dessa forma !? porque essa é a forma mais fácil, existem outras, podemos fazer por query string enviando o parâmetro handler com o nome do handler em questão.

Se esse handler for uma função, o que esperamos que seja, executamos ele passando os objetos request e response para poder manipular logo, não colocamos um monte de if’s dentro da closure ( fica feio não !? ), vamos adicionar cada handler necessário no objeto de forma diferente ! então, vamos ter o seguinte código

var messages = [ ] , callbacks = [ ] ;

handlers [ '/message' ] = function ( request , response ) {
       var message = url.parse ( request.url , true ).query.text ;
       var $ = {
              text : message.toString ( ) ,
              appendMessage : function ( callBack ) {
                     messages.push ( this ) ;
                     callBack ( this ) ;
              }
       }.appendMessage ( function ( message ) {
              while ( callbacks.length > 0 ) {
                     callbacks.shift ( ).callBack ( [ message ] ) ;
              }
       } ) ;
       response.writeHead ( 200 , { } ) ;
       response.end ( null ) ;
} ;

Primeira parte feita, criei um array para mensagens ( o que será armazenado nele ? todas as mensagens que são enviadas, ficam ali ), vocês podem colocar um setInterval para remover as mensagens a cada 1 minuto, pra não manter um array enorme de mensagens antigas :P , então crio um objeto que representa uma mensagem, nesse objeto, tem o método appendMessage que é executado após a criação do objeto, esse método adiciona a mensagem na lista (this) e executa o callBack passado por parâmetro, essa é a parte mais importante para tudo funcionar corretamente

O callBack .. o que é, e pra que serve nesse contexto ?

O callback é quem vai notificar todas as conexões abertas, e é exatamente por isso que ele é executado quando uma mensagem é adicionada, se uma mensagem é adicionada, algo mudou no servidor, temos então que notificar aos clientes que esperam esta mudança acontecer, se não notificarmos, o cliente vai ficar com a conexão aberta esperando uma resposta que sabemos que não será enviada. Portanto, chamamos o callback logo após a mensagem ser adicionada na lista

Temos então, a parte que envia a mensagem, deixando claro aqui também, lembre-se de emitir um HTTP-Code 200 para que a conexão não fique aberta, por isso emito o header e executo o método end pra enviar a resposta para o requisitante e fechar a conexão, agora a parte que faz o polling:

handlers [ '/polling' ] = function ( request , response ) {
       if ( messages.length === 0 ) {
              callbacks.push ( {
                     callBack : function ( $messages ) {
                            response.send ( 200 , {
                                   messages : $messages
                            } , 'text/json' ) ;
                     }
              } ) ;
       } else {
              response.send ( 200 , {
                     'messages' : messages
              } , 'text/json' ) ;
              messages = [ ] ;
       }
} ;

Simples não !? verifico se o array de mensagens é vazio, se for adiciono um cliente esperando resposta na lista de callBacks, porque este deve manter a conexão, observem também que eu NÃO dou fim na requisição, a função callBack que é adicionada na lista só é chamada quando uma mensagem é enviada ( algo muda no servidor ) , então o próprio servidor já vai notificar quando houver novas mensagens, caso o array já tenha mensagens, respondo a requisição e mando as mensagens que estão no array, logo após limpo a lista de mensagens, no lado do cliente teríamos algo semelhante ao seguinte fragmento de código

$ ( document ).ready ( function ( ) {
       function startPolling ( data ) {
              if ( data instanceof Object ) {
                     for ( var i in data.messages ) {
                            // ... exibe as mensagens
                     }
              }
              $.ajax ( {
                     url : 'http://127.0.0.1:8080/polling' ,
                     method : 'GET' ,
                     success : function ( data ) {
                            startPolling ( data ) ;
                     }
              } ) ;
       }
} ) ;

O que vai acontecer ? vamos requisitar novas mensagens quando houver, essas mensagens serão mostradas e vamos requisitar de novo procurando por novas, só que a conexão vai ficar aberta, até termos novas mensagens e enquanto a conexão estiver aberta uma nova não é criada, no console do google chrome aba network, mostra que não estamos trafegando dado algum, mas a requisição está pendente ou seja, esperando uma resposta

Demonstração rápida com cURL

Uma breve demonstração disto em ação, pode ser feita utilizando cURL, vou abrir 4 janelas do prompt-de-comando, em três delas, eu vou iniciar o polling, e na última, vou enviar uma mensagem, observem o resultado

-- Janela 1
C:>curl http://127.0.0.1:8080/polling
{"messages":[{"text":"Hello!"}]}
-- Janela 2
C:>curl http://127.0.0.1:8080/polling
{"messages":[{"text":"Hello!"}]}
-- Janela 3
C:>curl http://127.0.0.1:8080/polling
{"messages":[{"text":"Hello!"}]}
-- Janela 4
C:>curl http://127.0.0.1:8080/message?text=Hello!

Bem legal não é !? e você, sabe outra técnica ? alguma dica para melhorar o long-polling ? apresente-se !