<?php
/**
* Class Loader for PHP applications
*
* Provides an easy way for make the PHP code independent from the physical
* location where are located the php files containing the classes
* definitions of your app.
*
* It uses an internal structure with the real location of every class available. This
* structure is build searching in configurable locations for files with name ".class.php",
* both configurable, and saving it to file, to avoid the search in any execution.
*
* The main advantage that offers is that it allows us to free the application from
* the specific location of the classes, so we can move the classes between different
* folders or rearrange them without modify the code of the application
*
* LICENCE
* ========
* copyright (c) 2000 Patxi Echarte [hide@address.com]
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details at
* http://www.gnu.org/copyleft/lgpl.html
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* @package ClassLoader
* @version $Id: ClassLoader.class.php,v 1.4 2006/02/23 $
* @author Patxi Echarte <hide@address.com>
*
*/
class ClassLoader{
/**
* Almacena cada ruta sobre la que hay que buscar clases indicando
* si la búsqueda debe ser recursiva (1) o no (0)
* [[path,recursive{0,1}]]
*/
var $_paths = null;
/**
* Patrón que deben cumplir los archivos para considerarse como clases
*/
var $_patternClassName = "";
/**
* Matriz con las clases encontradas, se guarda como clave el nombre
* del archivo (NO el de la clase almacenada en el archivo) y como
* valor el del path donde está ubicada
*/
var $_classes = null;
/**
* Tiempo en segundos de validez de la información obtenida
*/
var $_expirationTime = 3600;
/**
* Nombre del archivo donde guardar la información de caché
*/
var $_cacheFileName = "";
/**
* Constructor de la clase
*
* @param $paths
* @param $pattern
* @param $cache_name
* @param $cache_folder
*/
function ClassLoader($exp=3600, $cache_name='classLoader.dat', $cache_folder='/tmp', $pattern='\.class\.php$')
{
$this->_expirationTime = $exp;
$this->_cacheFileName = realpath($cache_folder).'/'.$cache_name;
$this->_patternClassName = $pattern;
}
/**
* Añade un path
* @param string $path ruta completa desde la raíz del sistema
* @param bool $recursive (1|0) que indica si hay que buscar clases
* de manera recursiva en el path
*/
function addPath($path, $recursive=1)
{
if(ereg('\/$',$path)) $path = substr($path,0,-1);
if(!file_exists($path))
trigger_error("No existe el path indicado: [$path]", E_USER_ERROR);
else
$this->_paths[] = array(realpath($path), $recursive);
}
/**
* Pone en marcha el cargador de clases, para lo cual se buscan las clases
* disponibles o se recuperan de caché
*/
function start()
{
if(!$this->_getCachedData()){
$this->_rebuildClassesInfo();
$this->_setCachedData();
}
}
/**
* Busca clases en las ubicaciones que se han indicado
*/
function _rebuildClassesInfo()
{
$this->_classes = array();
foreach($this->_paths as $path_info){
$this->_searchDir($path_info[0], $path_info[1]);
}
}
/**
* Función recursiva, que dado un directorio busca en él y en todos sus hijos (si así se indica)
* archivos que cumplan con el patrón indicado, almacenando cada coincidencia en la matriz de clases
*/
function _searchDir($directory, $recursive=1){
if ($id_dir = @opendir($directory)){
while (false !== ($file = readdir($id_dir))){
if ($file != "." && $file != ".."){
if($recursive && is_dir($directory.'/'.$file)){
$this->_searchDir($directory.'/'.$file, $recursive);
}
else{
if(ereg($this->_patternClassName, $file)) {
if(isset($this->_classes[$file]) && $this->_classes[$file] != ''){
trigger_error("Se ha encontrado un archivo de clase "
."duplicada [$directory/$file]: ".$this->_data[$file],
E_USER_ERROR);
}
else
$this->_classes[$file] = realpath($directory.'/'.$file);
}
}
}
}
closedir($id_dir);
}
}
/**
* Devuelve el path del archivo de clase indicada
*/
function getPathForClass($cln){
return $this->_data[$cln];
}
/**
* Incluye el archivo necesario para tener disponibles la clase/s que contiene
*/
function includeClass($cln){
if(!isset($this->_classes[$cln]) || $this->_classes[$cln]==''){
trigger_error("La clase indicada no está definida: ".$cln);
}
else{
include_once($this->_classes[$cln]);
}
}
/**
* se realiza la inclusión de todas las clases encontradas
*/
function includeAllClasses(){
foreach($this->_classes as $name => $path)
include_once($path);
}
/**
* Comprueba si hay información en caché y si es válida, en cuyo caso la carga
* y devuelve true, eoc devuelve false
*/
function _getCachedData()
{
if( ! file_exists($this->_cacheFileName)
|| (filemtime($this->_cacheFileName) < time()-$this->_expirationTime) ){
return false;
}
$fp = fopen($this->_cacheFileName, 'r');
$this->_classes = unserialize(fread($fp, filesize($this->_cacheFileName)));
fclose($fp);
return true;
}
/**
* Almacena la información de clases en caché para no tener que realizar
* la búsqueda de clases en cada petición de páginas
*/
function _setCachedData()
{
if($fp = fopen($this->_cacheFileName, 'w')){
flock($fp, LOCK_EX);
fwrite($fp,serialize($this->_classes));
flock($fp, LOCK_UN);
fclose($fp);
}
}
}
?>