| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 | <?phpclass LtAutoloader{	public $conf = array(	/**	 * 是否自动加载定义了函数的文件	 *	 * 可选项: 	 * # true   自动加载 	 * # false  跳过函数,只自动加载定义了class或者interface的文件	 */		"load_function" => true,	/**	 * 要扫描的文件类型	 *	 * 若该属性设置为array("php","inc","php3"), 	 * 则扩展名为"php","inc","php3"的文件会被扫描, 	 * 其它扩展名的文件会被忽略	 */		"allow_file_extension" => array("php", "inc"),	/**	 * 不扫描的目录	 *	 * 若该属性设置为array(".svn", ".setting"), 	 * 则所有名为".setting"的目录也会被忽略	 */		"skip_dir_names" => array(".svn"),	);	public $storeHandle;	public $autoloadPath;	protected $functionFileMapping;	protected $fileStore;	public function init()	{		if (!is_object($this->storeHandle))		{			$this->storeHandle = new LtStoreMemory;			$this->fileStore = new LtStoreFile;			$this->fileStore->prefix = 'LtAutoloader-token-cache';			$this->fileStore->useSerialize = true;			$this->fileStore->init();		}		// Whether scanning directory		if (0 == $this->storeHandle->get(".class_total") && 0 == $this->storeHandle->get(".function_total"))		{			$this->storeHandle->add(".class_total", 0);			$this->storeHandle->add(".function_total", 0);			$this->storeHandle->add(".functions", array(), 0);			$autoloadPath = $this->preparePath($this->autoloadPath);			foreach($autoloadPath as $key => $path)			{				if (is_file($path))				{					$this->addFileMap($path);					unset($autoloadPath[$key]);				}			}			$this->scanDirs($autoloadPath);			unset($autoloadPath);		}		// Whether loading function files		if ($this->conf["load_function"])		{			$this->loadFunction();		}		spl_autoload_register(array($this, "loadClass"));	}	public function loadFunction()	{		if ($functionFiles = $this->storeHandle->get(".functions"))		{			foreach ($functionFiles as $functionFile)			{				include($functionFile);			}		}	}	public function loadClass($className)	{		if ($classFile = $this->storeHandle->get(strtolower($className)))		{			include($classFile);		}	}	protected function convertPath($path)	{		$path = str_replace("\\", "/", $path);		if (!is_readable($path))		{			trigger_error("Directory is not exists/readable: {$path}");			return false;		}		$path = rtrim(realpath($path), '\\/');		if ("WINNT" != PHP_OS && preg_match("/\s/i", $path))		{			trigger_error("Directory contains space/tab/newline is not supported: {$path}");			return false;		}		return $path;	}	/**	 * The string or an Multidimensional array into a one-dimensional array	 *	 * @param array $ or string $var	 * @return array one-dimensional array	 */	protected function preparePath($var)	{		$ret = array();		if (!is_array($var))		{			$var = array($var);		}		$i = 0;		while (isset($var[$i]))		{			if (!is_array($var[$i]) && $path = $this->convertPath($var[$i]))			{				$ret[] = $path;			}			else			{				foreach($var[$i] as $v)				{					$var[] = $v;				}			}			unset($var[$i]);			$i ++;		}		return $ret;	}	/**	 * Using iterative algorithm scanning subdirectories	 * save autoloader filemap	 *	 * @param array $dirs one-dimensional	 * @return	 */	protected function scanDirs($dirs)	{		$i = 0;		while (isset($dirs[$i]))		{			$dir = $dirs[$i];			$files = scandir($dir);			foreach ($files as $file)			{				if (in_array($file, array(".", "..")) || in_array($file, $this->conf["skip_dir_names"]))				{					continue;				}				$currentFile = $dir . DIRECTORY_SEPARATOR . $file;				if (is_file($currentFile))				{					$this->addFileMap($currentFile);				}				else if (is_dir($currentFile))				{					// if $currentFile is a directory, pass through the next loop.					$dirs[] = $currentFile;				}				else				{					trigger_error("$currentFile is not a file or a directory.");				}			} //end foreach			unset($dirs[$i]);			$i ++;		} //end while	}	protected function parseLibNames($src)	{		$libNames = array();		$tokens = token_get_all($src);		$level = 0;		$found = false;		$name = '';		foreach ($tokens as $token)		{			if (is_string($token))			{				if ('{' == $token)				{					$level ++;				}				else if ('}' == $token)				{					$level --;				}			}			else			{				list($id, $text) = $token;				if (T_CURLY_OPEN == $id || T_DOLLAR_OPEN_CURLY_BRACES == $id)				{					$level ++;				}				if (0 < $level)				{					continue;				}				switch ($id)				{					case T_STRING:						if ($found)						{							$libNames[strtolower($name)][] = $text;							$found = false;						}						break;					case T_CLASS:					case T_INTERFACE:					case T_FUNCTION:						$found = true;						$name = $text;						break;				}			}		}		return $libNames;	}	protected function addClass($className, $file)	{		$key = strtolower($className);		if ($existedClassFile = $this->storeHandle->get($key))		{			trigger_error("duplicate class [$className] found in:\n$existedClassFile\n$file\n");			return false;		}		else		{			$this->storeHandle->add($key, $file);			$this->storeHandle->update(".class_total", $this->storeHandle->get(".class_total") + 1);			return true;		}	}	protected function addFunction($functionName, $file)	{		$functionName = strtolower($functionName);		if (isset($this->functionFileMapping[$functionName]))		{			$existedFunctionFile = $this->functionFileMapping[$functionName];			trigger_error("duplicate function [$functionName] found in:\n$existedFunctionFile\n$file\n");			return false;		}		else		{			$this->functionFileMapping[$functionName] = $file;			$this->storeHandle->update(".functions", array_unique(array_values($this->functionFileMapping)));			$this->storeHandle->update(".function_total", count($this->functionFileMapping));			return true;		}	}	protected function addFileMap($file)	{		if (!in_array(pathinfo($file, PATHINFO_EXTENSION), $this->conf["allow_file_extension"]))		{			return false;		}		$libNames = array();		if ($this->fileStore instanceof LtStore)		{			$cachedFileLastModified = (int) @filemtime($this->fileStore->getFilePath($file));			if ($cachedFileLastModified < filemtime($file) || !is_array(($libNames = $this->fileStore->get($file))))			{				$libNames = $this->parseLibNames(trim(file_get_contents($file)));				if (0 < $cachedFileLastModified)				{					$this->fileStore->update($file, $libNames);				}				else				{					$this->fileStore->add($file, $libNames);				}			}		}		else		{			$libNames = $this->parseLibNames(trim(file_get_contents($file)));		}		foreach ($libNames as $libType => $libArray)		{			$method = "function" == $libType ? "addFunction" : "addClass";			foreach ($libArray as $libName)			{				$this->$method($libName, $file);			}		}		return true;	}}
 |