Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Woinch

[Resolvido] Problemas com namespaces ou spl_autoload

Recommended Posts

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

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

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

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

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

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

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

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

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

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.