Woinch 0 Denunciar post Postado Julho 18, 2012 Pessoal, acho que estou tendo um problema na utilização de namespaces. Não sei se não pode ser no spl_autoload onde não estou carregando corretamente o arquivo referente a classe. Alguém poderia me ajudar? Esse é o erro que me retorna: Fatal error: Class 'Modelos\Pessoa' not found in /Users/guiwunsch/Projetos/Sigest/Src/tests/test.php on line 14 Vejam o meu código (tentei resumir o máximo possível): Arquivo index.php: <?php use Config\Carregador, Modelos\Pessoa; require_once __DIR__ . '/../config/Carregador.Class.php'; //$carregador = Carregador::getInstance(); $carregador = new Carregador(); $carregador->incDiretorioRegistrado(__DIR__ . '/../*'); $carregador->incDiretorioIgnorado(__DIR__ . '/../libs/doctrine-orm/*'); $carregador->registrar(); $pessoa = new Pessoa(); $pessoa->setNome("Guilherme"); $pessoa->setVinculo(array(VINCULO_CLIENTE)); ?> Arquivo Pessoa.Class.php: <?php namespace Modelos; //use Modelos\Interfaces\IVinculo; class Pessoa //implements IVinculo { private $nome; private $cpf; private $rg; public function Pessoa() { } public function setNome($nome) { $this->nome = $nome; } public function getNome() { return $this->nome; } public function setCpf($cpf) { $this->cpf = $cpf; } public function getCpf() { return $this->cpf; } public function setRg($rg) { $this->rg = $rg; } public function getRg() { return $this->rg; } public function setVinculo($vinculo) { $this->vinculo = $vinculo; } } Arquivo Carregador.Class.php: <?php namespace Config; //use Libs\Singleton; //require_once(__DIR__ . "/../libs/Singleton.Class.php"); class Carregador //extends Singleton { private $diretoriosRegistrados = array(); private $diretoriosIgnorados = array(); private $preparado; /* * Responsável por carregar automaticamente os arquivos PHP do sistema para que não seja necessário * efetuar inclusões exaustivas desses arquivos. */ protected function Carregador() { parent::Singleton(); $this->preparado = false; } /* * Prepara a lista de diretórios para adicionar na include path. */ private function preparar() { $incDir = array(); $excDir = array(); // Monta lista unificada com todos os diretórios registrados foreach ($this->diretoriosRegistrados as $dir) { if (substr($dir, -1) == '*') { $dir = substr($dir, 0, -1); $incDir = $this->varrerDiretorio($dir, $incDir); } elseif (is_dir($dir) && is_readable($dir)) { $incDir[] = $dir; } } // Monta lista unificada com todos os diretórios a serem ignorados foreach ($this->diretoriosIgnorados as $dir) { if (substr($dir, -1) == '*') { $dir = substr($dir, 0, -1); $excDir = $this->varrerDiretorio($dir, $excDir); } elseif (is_dir($dir) && is_readable($dir)) { $excDir[] = $dir; } } // Faz o merge das duas listas para montar o include path $path = ''; foreach ($incDir as $dir) { if (!in_array($dir, $excDir)) $path .= PATH_SEPARATOR . $dir; } set_include_path(get_include_path() . $path); $this->preparado = true; } /* * Varre diretórios recursivamente para montar lista. * * @parametro string $dirRaiz Diretório onde irá começar a busca recursiva * @parametro array string $todoConteudo Lista de entrada que será concatenada a busca recursiva * @retorno array string Lista com todos os diretórios encontrados */ private function varrerDiretorio($dirRaiz, $todoConteudo = array()) { if (is_dir($dirRaiz) && is_readable($dirRaiz)) { $todoConteudo[] = $dirRaiz; $nomesInvisiveis = array(".", "..", ".htaccess", ".htpasswd"); $conteudoDir = scandir($dirRaiz); foreach ($conteudoDir as $key => $conteudo) { if (!in_array($conteudo, $nomesInvisiveis)) { $dir = $dirRaiz . $conteudo . '/'; $todoConteudo = $this->varrerDiretorio($dir, $todoConteudo); } } } return $todoConteudo; } /* * Adiciona diretório na lista de procura. * * @parametro string $dir Diretório */ public function incDiretorioRegistrado($dir) { $this->diretoriosRegistrados[] = $dir; $this->preparado = false; } /* * Adiciona diretório na lista de ignorados. * * @parametro string $dir Diretório */ public function incDiretorioIgnorado($dir) { $this->diretoriosIgnorados[] = $dir; $this->preparado = false; } /* * Registra essa classe na pilha de carregamento automático. */ public function registrar() { if (!$this->preparado) $this->preparar(); spl_autoload_register(array($this, "carregar")); } /* * Remove essa classe da pilha de carregamento automático. */ public function desregistrar() { spl_autoload_unregister(array($this, "carregar")); } /* * Carrega determinada classe ou interface. * * @parametro string $classe Nome da classe para carregar. */ public function carregar($classe) { spl_autoload_extensions('.Class.php, .Inc.php'); spl_autoload($classe); } } ?> Compartilhar este post Link para o post Compartilhar em outros sites
Bruno Augusto 417 Denunciar post Postado Julho 18, 2012 Você precisa MESMO de tudo isso? Por que se você fizer a modificação do include_path manualmente como normalmente se faz, um código como esse: spl_autoload_register( function( $classname ) { $classname = stream_resolve_include_path( str_replace( '\\', DIRECTORY_SEPARATOR, $classname ) . '.php' ); if( $classname !== FALSE ) { include $classname; } } ); Já dá conta do recado. Compartilhar este post Link para o post Compartilhar em outros sites
Woinch 0 Denunciar post Postado Julho 18, 2012 Mas desse jeito eu não poderei utilizar namespaces, correto? A não ser que eu deixe os arquivos exatamente na mesma pasta dos namespaces, ou não? Compartilhar este post Link para o post Compartilhar em outros sites
Bruno Augusto 417 Denunciar post Postado Julho 18, 2012 Claro que pode. Inclusive, esse fragmento corresponde à um dos possíveis métodos de autoload que meu sistema suporta :thumbsup: Compartilhar este post Link para o post Compartilhar em outros sites
Woinch 0 Denunciar post Postado Julho 18, 2012 Mas como que ficaria o código Bruno? Esse que você me passou, se eu instanciar uma classe que esta no namespace Modelos, o parâmetro $classname vai vir com Modelos\Pessoa por exemplo, porém no meu caso essa classe está na pasta app\model\Pessoa.Class.php, portanto ele não encontra com esse código. Outro exemplo é uma classe que está no namespace Modelos\Interfaces\IVinculo e fisicamente está localizada em app\model\IVinculo.Class.php Como ficaria o código do spl_autoload_register que consiga encontrar essas classes? Obrigado. Compartilhar este post Link para o post Compartilhar em outros sites
Bruno Augusto 417 Denunciar post Postado Julho 18, 2012 Foi justamente por isso que, felizmente, eu lembrei de adicionar essa nota no meu post: Por que se você fizer a modificação do include_path manualmente como normalmente se faz... Com isso, você instruirá onde as classes serão buscadas para inclusão. Então se app\model é um dos diretórios adicione-o ao include_path: set_include_path( '.' . PATH_SEPARATOR . __DIR__ . DIRECTORY_SEPARATOR . 'app/model' . PATH_SEPARATOR . get_include_path() ); Como estou sem servidor PHP 5.3 aqui eu apenas imagino que isto seja suficiente, adapte de acordo com sua necessidade. :thumbsup: Compartilhar este post Link para o post Compartilhar em outros sites
Woinch 0 Denunciar post Postado Julho 18, 2012 Eh justamente assim que estou fazendo, como pode ver no codigo em: $carregador->incDiretorioRegistrado(__DIR__ . '/../*'); ... $carregador->registrar(); O método registrar chama o preparar que por sua vez inclui todos os diretórios da minha app no include_path. Pelo que testei, a app não encontra a classe quando vem com o namespace, somente se eu não utiliza-lo, porém com isso vai me dar outro problema, pois isso me impossibilitará de ter duas classes com o mesmo nome. Tem alguma dica? Obrigado. Acabo de verificar que somente é possível carregar a classe dessa maneira com o namespace = nome da pasta. Alguém utiliza as funções spl_* com namaspace diferente do nome da pasta? Poderia nos passar exemplos? Obrigado. Compartilhar este post Link para o post Compartilhar em outros sites
Bruno Augusto 417 Denunciar post Postado Julho 18, 2012 Acabo de verificar que somente é possível carregar a classe dessa maneira com o namespace = nome da pasta. Alguém utiliza as funções spl_* com namaspace diferente do nome da pasta? Poderia nos passar exemplos? Obrigado. Dada a simplicidade da implementação, isso é o esperado. O autoload vai funcionar de acordo com as regras que você especificar. Se você quer algo que foge um pouco do tradicional, basta codificar tais regras. Tudo é válido, usar strpos() para buscar algum termo específico no nome da classe, usar Reflection e etc. Enfim... Mas essa abordagem te trás pelo menos dois problemas: 1. Sua codificação se torna dependente demais da estrutura de arquivos e diretórios. Uma nomeclatura que você resolva mudar por harmonia léxica (eu tenho muito disso :closedeyes:) e já era, você vai ser obrigado a mexer no código de autoloading. 2. Performance! Incluir um arquivo é uma tarefa bastante custosa para a aplicação. Quanto mais complexo for o procedimento para localizar as classes, pior vai ser. Isso sem contar o fato de que você estaria criando um padrão único e específico para sua aplicação, o que nem sempre é uma boa coisa. É como dizem... KISS: Keep it simple, stupid! Compartilhar este post Link para o post Compartilhar em outros sites
Woinch 0 Denunciar post Postado Julho 18, 2012 Está certo. Já estou convencido. Vou seguir com a ideia de manter o namespace = diretório em disco. Obrigado pela atenção. Compartilhar este post Link para o post Compartilhar em outros sites