Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
Eai galera, tudo certinho?
Estou particularmente "começando" no mundo OO. Já adquiri algum conhecimento na área e por isso vou ser mais ativo por aqui no forum :b
Eu sei que pra definir um namespace no PHP é basicamente isso:
namespace Projeto;
class MinhaClasse {
// conteúdo;
}
Mas minha dúvida é a seguinte: Quero definir um namespace pra varias classes ao mesmo tempo, sendo que todas elas estariam dentro ou incluídas(include/require) em um único arquivo, pra não precisar fazer isso ai de cima pra cada nova classe ou função. Já pesquisei sobre o assunto e não obtive sucesso, talvez por não saber me referir corretamente.
Já vi em algum lugar a seguinte sintaxe:
namespace Projeto {
class MinhaClasse {
// conteúdo;
}
}
E eu quero algo assim:
namespace Projeto {
class MinhaClasse {
// conteúdo;
}
class MinhaSegundaClasse {
// conteúdo;
}
}
Não sei se eu estou viajando e é tudo da minha cabeça, pois o PHP não está reconhecendo a classe com o namespace definido dessa forma. Eu estou usando o PHP 5.3.8.
Me ajudem por favor,
Vlw ai galera :b
Não coloque 2 classes por aquivo.
No arquivo Class1.php faça:
namespace myNamespace;
class Class1 {
}
No arquivo Class2.php faça:
namespace myNamespace;
class Class2 {
}
Cara,
Assim funciona :clap: .
Estava tentando assim só que ao invés das classes estarem em um mesmo arquivo eu incluo elas de arquivos separados, assim:
namespace Projeto:
require 'projeto/minha.class.php';
require 'projeto/minhaSegunda.class.php';
Só que dessa forma as classes não são encontradas :/
Acho que o correto é você sempre definir o namespace no mesmo arquivo da classe e imediatamente antes dela, por isso deve estar dando erro.
>
Não coloque 2 classes por aquivo.
No arquivo Class1.php faça:
namespace myNamespace;
class Class1 {
}
No arquivo Class2.php faça:
namespace myNamespace;
class Class2 {
}
Henrique,
É exatamente isso que eu não quero fazer: Definir um namespace antes de toda classe, entendeu?
Já tentei definir uma variável no lugar do namespace e no arquivo de inclusão dar um valor a ela, mas o php não aceita.
Arquivo: minha.class.php;
namespace $ns;
class MinhaClass {
// Conteúdo;
}
Arquivo que junta as classes;
$ns = 'Projeto';
require "projeto/minha.class.php";>
Já tentei definir uma variável no lugar do namespace e no arquivo de inclusão dar um valor a ela, mas o php não aceita.
Mas aí você já está inventando moda... hahaha
Tem que fazer o que está documentado no manual. :P
Henrique, ele quer definir UM namespace para várias classes ..
Não tem problema nenhum ter duas classes no mesmo namespace .. arquivo Namespace.php
<?php
namespace Nspace ;
class X { }
class Y { }
class Z { }
Arquivo índice
<?php
use Nspace as Ns ;
var_dump ( new Ns\X , new Ns\Y , new Ns\Z ) ;
Saída
object(Nspace\X)#1 (0) {
}
object(Nspace\Y)#2 (0) {
}
object(Nspace\Z)#3 (0) {
}
>
Mas aí você já está inventando moda... hahaha
Tem que fazer o que está documentado no manual. :P
Hahahaha,
Bendito manual, foi o primeiro que eu consultei.
Mas tipo, ainda restava alguma esperança em mim.
Vlw pela ajuda pessoal :D
>
Henrique,
É exatamente isso que eu não quero fazer: Definir um namespace antes de toda classe, entendeu?
Já tentei definir uma variável no lugar do namespace e no arquivo de inclusão dar um valor a ela, mas o php não aceita.
Arquivo: minha.class.php;
namespace $ns;
class MinhaClass {
// Conteúdo;
}
Arquivo que junta as classes;
$ns = 'Projeto';
require "projeto/minha.class.php";
Você disse que não quer ficar definindo o namespace dentro de cada classe, mas mesmo assim fica digitando require para pegar essa classe... Ao meu vê, é o mesmo trabalho.
Se você quiser tirar o máximo proveito do autoloader, você deve seguir as boas práticas, e as boas práticas dizem que você deve definir apenas um namespace por classe/arquivo.
Henrique, ele quer definir UM namespace para várias classes .. Não tem problema nenhum ter duas classes no mesmo namespace .. arquivo Namespace.php
Tá e o recurso de autoloading fica onde?
O padrão é 1 classe por aquivo.
Em Java temos que declarar o pacote ao qual a classe pertence em TODOS os arquivos, dar import das bibliotecas necessárias em TODOS os arquivos. Não existe mágica...
Acontece, Henrique, que utilizando-se dessa técnica você consegue abolir o autoload tornando o sistema, seja ele qual for, três vezes mais rápido.
Pena é que existe um bug, que eu mesmo reportei, que impede a técnica de ser plenamente funcional sob todos os aspectos da Orientação a Objetos.
>
Acontece, Henrique, que utilizando-se dessa técnica você consegue abolir o autoload tornando o sistema, seja ele qual for, três vezes mais rápido.
Aí também depende do tamanho da aplicação, se você tiver uma aplicação muito grande, vamos supor com centenas de classes, e colocar todas essas classes dentro de um único arquivo, você estará desperdiçando o uso da memória do servidor, pois você terá que incluir toda vez um arquivo gigante com centenas de classes onde a maioria não será usada no mesmo momento.
Também concordo que, por questões de organização, cada classe deva estar em um arquivo distinto. Mas como cada caso é um caso, aí fica por conta do autor do tópico ver qual é a melhor solução pro caso dele.
Sim, sim. Mas se você tiver, por exemplo, todas as classes de um mesmo módulo num mesmo namespace, você invoca um único use e garante acesso à todas as classes do pacote.
Ainda haverá algum tipo de desperdício que será compensado na performance geral.
A ideia do Bruno é até interessante, mas não para o desenvolvimento. Ao meu ver, deveria se desenvolver com cada classe em um arquivo separado. Ao final do desenvolvimento, seria feita uma "compilação", de preferência de forma automática, deixando cada namespace dentro de um só arquivo, com todas as classes, sem quebras de linhas. Nunca testei, mas sempre achei que isto melhoraria o desempenho. Só que isto gerará um problema, que o Bruno citou acima e que foi identificado por ele em outro tópico que falamos sobre isto, sobre um erro com as interfaces.
Alguém já tentou fazer desta forma e fez algum tipo de teste? Seria legal para vermos se existe ganho de desempenho ou se não faz diferença.
Carlos Eduardo
Já que você quer evitar o autoload por considerar que ele faz a aplicação perder performance, eu acho melhor você deixar as classes em cada arquivo separado e abusar do uso dos requires.
As classes essenciais para o funcionamento da aplicação, como por exemplo conexão com banco de dados, manipulação de sessões, registry, etc, você pode incluir no próprio bootstrap da aplicação. Já as outras classes mais específicas você vai incluindo na medida que for necessário usá-las.
Essa é só a minha opinião, pois acho essa de incluir mais de uma classe no mesmo arquivo muito desorganizado e foge um pouco dos padrões da orientação a objetos.
>
Tá e o recurso de autoloading fica onde?
Ele não perguntou sobre autoload, e sim como colocar várias classes em um único namespace, essa pergunta foi respondida e ponto.
;)
A ideia do Bruno é até interessante, mas não para o desenvolvimento.
Com toda certeza. Faltou mencionar isso ^_^
Prestar manutenção, quando em desenvolvimento, num arquivo de 10 mil linhas (ou mais) é froids...
>
Ao final do desenvolvimento, seria feita uma "compilação", de preferência de forma automática, deixando cada namespace dentro de um só arquivo, com todas as classes, sem quebras de linhas.
Eu quase consegui, mas esbarrei naquele problema.
Alguém já tentou fazer desta forma e fez algum tipo de teste? Seria legal para vermos se existe ganho de desempenho ou se não faz diferença.
Eu testei. Quando meu AB rodava direitinho no Windows Seven, fiz um teste "folgado", algo em torno de 100 requisições com 50 de concorrência e foi três vezes mais rápido. Isso nas configurações bem abaixo do normal do notebook que eu uso. :cry:
Daí eu andei lendo a respeito e parece que isso acontece não por causa do PHP em si, que tem de incluir diversos arquivos, mas sim com o Servidor que quando "recebe" uma instrução com relação ao Sistema de Arquivos executa algum comando antes de, de fato, incluir.
Não lembro direito, acho que seria algo similar ao lstat() do PHP...
Captei a idéia de vocês, seria reunir automaticamente todas as classes em um único arquivo somente para ambiente de produção. ^_^
Realmente interessante isso, mas somente se não forem muitas classes, se não como eu disse vai ter um desperdiço muito grande de memória aí.
EDIT:
Só espero que o mestre dos padrões (João Batista Neto) não arrance os seus cabelos ao ler este tópico. haha
Acontece, Henrique, que utilizando-se dessa técnica você consegue abolir o autoload tornando o sistema, seja ele qual for, três vezes mais rápido.
Três vezes mais rápido por quê?
Se você usar um autoload 'burro' que fica escaneando diretórios toda vez para procurar classes, perde performance mesmo.
Eu crio um 'cache' em um registro de todas as classes e caminhos para elas na minha aplicação logo no início da execução. Toda a classe que for carregada apenas vai nesse registro e inclui o arquivo correto. Esse registro nada mais é que uma tabela hash, logo, o tempo de acesso é constante.
Na verdade, já até pensei em colocar isso numa sessão para executar uma vez só, o problema seria a segurança, já que a sessão é armazenada no cliente.
Em termos de manutenibilidade, se perde muito ao termos várias classes em um arquivo só.
Ele não perguntou sobre autoload, e sim como colocar várias classes em um único namespace, essa pergunta foi respondida e ponto.
Então agora é assim? Vê alguém fazendo uma cagada, você não fala nada? Ou pior, incentiva?
Desculpa, mas tem certas coisas com as quais eu não consigo concordar.
>
Então agora é assim? Vê alguém fazendo uma cagada, você não fala nada? Ou pior, incentiva?
Ninguém fez cagada,
Isso não foi questionado, a maioria das vezes que tentei fazer o melhor possível em relação as perguntas, aos possíveis problemas futuros, e implementações melhores, eu fui criticado .. também não incentivei ninguém, respondi o que foi perguntado, até acho melhor agente parar por aqui
>
Acontece, Henrique, que utilizando-se dessa técnica você consegue abolir o autoload tornando o sistema, seja ele qual for, três vezes mais rápido.
>
Também concordo que, por questões de organização, cada classe deva estar em um arquivo distinto. Mas como cada caso é um caso, aí fica por conta do autor do tópico ver qual é a melhor solução pro caso dele.
>
Já que você quer evitar o autoload por considerar que ele faz a aplicação perder performance, eu acho melhor você deixar as classes em cada arquivo separado e abusar do uso dos requires.
Aí aparece a questão.
Será que perfomance é mais importante que organização?
Entre as duas eu fico com as duas. :P
Você pode muito bem deixar uma classe por arquivo, e manter a perfomance. Uma das alternativas é utilizar um Class Map, não sei se alguém citou isso, mas não li todos os posts.
E é exatamente isto que será usado na nova versão do ZF: http://framework.zend.com/wiki/display/ZFDEV2/Proposal+For+Autoloading+In+ZF2#ProposalForAutoloadingInZF2-ClassMapAutoloader
Acho que o pessoal não entendeu a ideia do Bruno.
Talvez em algum momento neste tópico tenha ficado mal explicado, mas a ideia dele é que, durante o desenvolvimento, se coloque uma classe por arquivo, como é o padrão.
Ao final, ou seja, na hora de implantar, faz-se uma "pseudo compilação" (automatizada), que seria fazer esta união de todas as classes do mesmo namespace em um arquivo só, mas sem perder as classes separadas. Ou seja, na hora de fazer manutenção, faz-se nos arquivos separados e depois se refaz a "compilação". Na verdade isto é algo que já se faz em linguagens compiladas. Seria mais ou menos a mesma ideia.
Eu fiz profile de alguns projetos meus com o Zend Framework. Não tenho o resultado aqui, mas lembro que o processo que levava mais tempo era o Loader de classes do ZF. Então, se a gente conseguir diminuir o impacto deste processo, talvez seja interessante. Não sei se seria realmente interessante, mas é algo que vale a pena avaliar, não acham?
Carlos Eduardo
No tempo que eu havia analisado no Zend Server, apenas o autoloader era mais de 300ms do tempo total de processamento. Eu creio que esse tempo ser é alto é pq era um HD normal, um SSD talvez ficaria apenas 1/3 desse tempo.
Nossa agora que vi meu erro grotesco de escrita. :o
Corrigindo: arranque*
É interessante como as coisas são.
Já pararam para pensar que há 5~6 anos atrás, esse tipo de discussãoseria inimaginável em um fórum de PHP! Tenho certeza que se surgisse uma discussão sobre empacotamento em PHP, alguém certamente diria: "Isso é coisa de Java".
O mais interessante é que, com a evolução da linguagem, problemas que até então não existiam, passam a existir:
Namespaces:
>
Quero definir um namespace pra varias classes ao mesmo tempo, sendo que todas elas estariam dentro ou incluídas(include/require) em um único arquivo pra não precisar fazer isso ai de cima pra cada nova classe ou função.
A primeira coisa que se precisa compreender é que namespace é a definição de contexto em linguagens de programação. Definir todas as classes dentro de um único namespace é um erro pois, dessa forma, perde-se a definição de contexto e, consequentemente, o sentido de se utilizar um namespace.
>
Não coloque 2 classes por aquivo.
Ai surge um outro problema: Porque colocar apenas 1 classe em um arquivo? Porque não devemos colocar mais do que uma classe no mesmo arquivo? Se o contexto estiver bem definido e o namespace representar corretamente aquele conjunto de classes, qual o problema em ter várias classes dentro de um único arquivo?
Há quem diga simplesmente: "Pois esse é o padrão!".
Okay, é o padrão, mas o que significa isso?
Um padrão não surge ao acaso. Antes de se ter um padrão, teremos sempre um problema. Esse problema chama-se manutenção: Escrever código orientado a objetos é difícil, mas manter um código desorganizado é impossível (do ponto de vista do alto custo de manutenção).
Vamos imaginar a seguinte situação: Temos um sistema de armazenamento de arquivos, fazemos download do arquivo "class" de uma origem, depois fazemos o download do arquivo "class" de outra origem:
[neto@localhost namespace]$ ls
class class(1)
Perceba que, para evitar a sobrescrita do identificador class, um nome diferente foi dado ao arquivo. Conforme as aplicações vão crescendo, identificadores homônimos vão se tornando cada vez mais prováveis e, resolver os problemas relacionados com colisão de nomes vão se tornando cada vez mais complexos. Porém, quando temos cada arquivo representando uma classe, fica mais fácil identificar o problema.
Imagine que tenhamos 2 diretórios: fruits e pasta:
Dentro do diretório fruits tenhamos os arquivos: Apple, Banana e Orange.
Dentro do diretório pasta tenhamos os arquivos: Capellini, Spaghetti e Penne.
[neto@localhost food]$ find
.
./pasta
./pasta/Capellini
./pasta/Penne
./pasta/Spaghetti
./fruits
./fruits/Apple
./fruits/Banana
./fruits/Orange
Perceba que, como os arquivos estão organizados, identificar algum problema é fácil. Não precisamos sair abrindo os arquivos que representam um namespace, basta listar os arquivos contidos em um diretório que representa um namespace que veremos as classes que estão contidas nesse namespace.
Porém, existe uma exceção à essa regra que justifica ter mais do que uma classe em um mesmo arquivo. Algumas vezes, uma abstração precisa oferecer uma implementação para uma operação e, quando apenas a abstração usa essa implementação, ela é feita no mesmo arquivo da abstração:
SomeInterface.php
<?php
namespace example;
interface SomeInterface {
public function doSomething();
}
Abstraction.php
<?php
namespace example;
abstract class Abstraction {
public abstract function helloWorld();
/**
* @return SomeInterface
*/
public function createSomething() {
return new SomeImplementation();
}
}
class SomeImplementation implements SomeInterface {
public function doSomething() {
echo 'Hello world!';
}
}
Concretion.php
<?php
namespace implementation;
use example\Abstraction;
class Concretion extends Abstraction {
public function helloWorld() {
$this->createSomething()->doSomething();
}
}
Como podemos ver, Concretion usa a implementação simples oferecida pela Abstraction, mas poderia também ter sua própria implementação. Como a interface SomeInterface está separada, Concretion pode ignorar a implementação simples oferecida por Abstraction e implementar SomeInterface para ter sua própria implementação.
Client.php
<?php
use example\Abstraction;
class Client {
public function usesAbstraction( Abstraction $a ) {
$a->helloWorld();
}
}
Para o Client, tanto faz quem ou como é implementado a operação helloWorld(), o Client apenas usa a operação e sequer tem conhecimento de que existe um outro participante envolvido. Nesses casos, quando uma implementação é oferecida por uma abstração e é usada somente por essa abstração, ter essa implementação no mesmo arquivo da abstração é completamente justificável.
Princípios de empacotamento:
>
Captei a idéia de vocês, seria reunir automaticamente todas as classes em um único arquivo somente para ambiente de produção. ^_^
Realmente interessante isso, mas somente se não forem muitas classes, se não como eu disse vai ter um desperdiço muito grande de memória aí.
Só espero que o mestre dos padrões (João Batista Neto) não arrance os seus cabelos ao ler este tópico. haha
Eu tenho créditos para arrancar os cabelos, quem já viu uma foto minha sabe do que estou falando. hehehe :P
Bom, agora chegamos na parte divertida da história, o empacotamento!!!
A primeira coisa que precisamos ter consciência aqui é que não existe mágica. Conforme a aplicação vai crescendo, a alta granularidade das classes pode se tornar um problema e, para isso, utilizamos um sistema de organização de nível mais alto. Um pacote é como uma caixa que contém vários recursos de um sistema, esses recursos devem ser agrupados de forma lógica e segundo alguns princípios.
:seta: Quem desenvolve aplicações orientadas a objetos e nunca ouviu falar de reutilização, que jogue o primeiro objeto.
Reutilização não é copiar um código de um lugar e colar em outro, reutilizar também não é fazer um clone um arquivo de um repositório para um projeto e utilizá-lo na aplicação. Reutilização é a capacidade de se utilizar um código sem precisar ler código. É a capacidade de se utilizar um código dependendo exclusivamente da abstração, sem precisar saber como é feita a implementação.
Sabemos que devemos depender de abstrações e não de implementações. E quando aos pacotes?
Quando utilizamos uma biblioteca empacotada, estamos utilizando as funcionalidades que ela oferece, por exemplo, eu desenvolvo um framework para construção de GUI:
Se eu empacotar esse framework e vendê-lo como uma biblioteca, o que você, como consumidor desse produto, espera?
Você espera que, caso eu lance uma nova versão dessa biblioteca, você possa se beneficiar dessa nova versão, você possa decidir entre utilizar a versão atual ou a nova versão, você espera ainda que a migração para a nova versão possa ocorrer apenas no momento que você tiver tempo disponível. De fato, você espera que possa utilizar essa versão apenas quando as mudanças que eu fiz na biblioteca interessarem à você.
Se você simplesmente copiar e colar um código que eu escrevi e usar na sua aplicação, você terá a preocupação em procurar as classes que eu modifiquei e fazer os ajustes necessários para que a nova versão funcione corretamente. Se eu fizer melhorias ou correções de bugs na biblioteca, você não será beneficiado de imediato por essas modificações. Com o tempo, muito possivelmente, sua versão será diferente da minha e, consequentemente, você deixará de se beneficiar dos novos recursos e bug fixes que eu fizer.
Mas, o que colocar em um pacote?
Esse problema já foi mencionado nesse tópico. Classes em um pacote são reutilizadas em conjunto, se você reutiliza uma classe de um pacote, você reutiliza todas. Esse deve ser o princípio base na hora de decidir o que colocar em um pacote. Se classes forem reutilizadas em conjunto, então elas deverão ser empacotadas em conjunto.
Como todo princípio, fica mais fácil perceber o fundamento quando estamos diante do problema, então, vamos ver um exemplo:
Perceba que, quando você for utilizar esse pacote, além de todas as classes de GUI, você estará utilizando também classes relacionadas com DBA, existe algum sentido nisso? Qual a relação existente entre um framework para construção de elementos de interface de usuário e um framework para abstração de bancos de dados?
Da mesma forma que temos o princípio da responsabilidade única (S.R.P.) para classes, temos o princípio da reutilização comum (C.R.P.) para pacotes, ou seja, um pacote precisa ser coeso. Se temos um pacote para construção de GUI, temos que ter dentro dele apenas coisas para construção de GUI.
O problema da falta de coesão é o mesmo que ocorre quando violamos o princípio da responsabilidade única. Quando uma nova versão da minha biblioteca é lançada, você terá que revalidar sua aplicação e ver se tudo está funcionando como deveria. Se eu empacoto coisas que não são coesas com o objetivo do pacote, uma mudança na minha camada de abstração com banco de dados poderá interferir na sua interface de usuário, ou seja, você será afetado por mudanças feitas em classes que você nem utiliza.
Manutenção de aplicações é cara, então é certo dizer que, mais importante que reutilização, é a manutenibilidade.
Uma mudança em uma classe do pacote afeta todas as classes do pacote então, de fato, classes em um pacote devem ser coesas, mas também precisam ser empacotadas de acordo com o tipo de mudança que elas sofrem. Se tivermos classes que mudam juntas, então elas devem ser empacotadas juntas, isso minimiza o esforço no processo de revalidação do sistema. Se tivermos N classes em um pacote e apenas 10 mudarem, todo o pacote precisará ser revalidado, por outro lado, se as 10 classes forem colocadas juntas em outro pacote, tudo fica mais simples.
Pacotes no PHP:
Desde a versão 5.3 o PHP introduziu nativamente os pacotes Phar. Um pacote Phar é, de certa forma, parecido com um pacote jar do Java.
Qual era a dúvida do tópico mesmo?
>
sendo que todas elas estariam dentro ou incluídas(include/require) em um único arquivo
hummmm....
>
What is phar? Phar archives are best characterized as a convenient way to group several files into a single file...
Então, além de já sabermos alguns princípios de empacotamento, temos uma solução nativa para o problema!!!
Vamos ver isso de perto, vamos empacotar nosso framework de gui:
[neto@localhost example]$ find com/imasters/gui
com/imasters/gui
com/imasters/gui/Component.php
com/imasters/gui/Composite.php
com/imasters/gui/Panel.php
Como podemos ver, temos 3 arquivos. Vamos escrever o código responsável pelo empacotamento:
<?php
$phar = new Phar( 'com.imasters.gui.phar' , 0 );
$phar->startBuffering();
$phar->buildFromIterator( new DirectoryIterator( 'com/imasters/gui' ) , '.' );
$phar->setStub( <<<'STUB'
<?php
Phar::interceptFileFuncs();
spl_autoload_register( function( $class ) {
$file = 'phar://' . __FILE__ . '/';
$file .= implode( DIRECTORY_SEPARATOR , explode( '\\' , $class ) );
$file .= '.php';
if ( is_file( $file ) ) {
require_once $file;
}
} );
__HALT_COMPILER(););
$phar->stopBuffering();
O resultado disso é um arquivo chamado: com.imasters.gui.phar. Utilizando o arquivo:
<?php
require_once 'com.imasters.gui.phar';
use com\imasters\gui\Panel;
$p = new Panel();
$p->addAttribute( 'id' , 'example' );
echo $p->draw();
Resultado:
[neto@localhost example]$ php test.php
<div id="example"></div>
O arquivo test.php faz o include apenas no pacote da biblioteca que contém todas as classes necessárias. Se distribuirmos esse pacote, qualquer pessoa poderá se beneficiar do framework de construção de GUI e, caso eu venha a lançar uma nova versão, bastará baixar a biblioteca e revalidar a aplicação.
De fato, empacotamento é um tema muito interessante (extenso também) e que será cada dia mais comum no universo PHP.
;)
Cara, eu também não tenho experiência com namespaces, pois comecei a estudar este recurso faz pouco tempo para trabalhar com a versão 2.0 do Zend Framework que vem por aí. Mas pelo o que eu já andei estudando no manual do PHP, esta sua sintaxe está errada, pois eu pelo menos não encontrei nada parecido na documentação.
Acredito que o correto seria assim:
namespace Projeto1;
class MinhaClasse1 {
}
class MinhaClasse2 {
}
namespace Projeto2;
class MinhaClasse1 {
}
class MinhaClasse2 {
}