PHP-php的自加载怎么用?

PHP-php的自加载怎么用?

甜柠檬 发布于 2017-07-17 字数 251 浏览 1107 回复 4

我在做一个框架,从入口文件进入之后调用到核心类的时候,居说有个factory的方法来调用这些类可以实现自加载,网上搜了没找到合适的方法。
我有一个入口文件 index.php,进入之后指向pub这个文件下的引文件进入lib核心类文件夹,并自动加载所需要的类,求助。

如果你对这篇文章有疑问,欢迎到本站 社区 发帖提问或使用手Q扫描下方二维码加群参与讨论,获取更多帮助。

扫码加入群聊

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

瑾兮 2017-10-26 4 楼

所有想自动加载的类 需要遵循某种统一的命名规则

我提供我写的一个通用的类加载类

 <?php
/**
* 自动加载类
*
*/
final class Core_Autoloader {

/**
* 类搜索路径
*
* @var array
*/
private static $_class_path = array();

/**
* 类搜索规则
*
* @var array
*/
private static $_locate_rules = array();

/**
* 添加一个类搜索路径
*
* @param string $dir 要添加的搜索路径
*/
static function import($dir)
{
$real_dir = realpath($dir);
if ($real_dir)
{
$dir = rtrim($real_dir, '/\') . DIRECTORY_SEPARATOR;
if (!isset(self::$_class_path[$dir]))
{
self::$_class_path[$dir] = $dir;
}
}
}

/**
* 返回 指定类的定义文件,此处并不检测类文件&类是否存在
*
* 对于 不属于类定位规则中定义的类,使用加载器缺省的加载机制,只显示 类名所表示的局部路径
*
* 例如: Pkg_Controller_Application => pkgcontrollerapplication.php
*
* @param string $class_name
* @param boolean $return 指示是否直接返回处理后的文件名,而不判断文件是否存在
*
* @return string
*/
static function getClassFile($class_name, $return = false){

foreach (self::$_locate_rules as $rule){
$filename = call_user_func($rule,$class_name);
if ($filename) break;
}

// 缺省的类加载规则
if (!isset($filename))
$filename = str_replace('_', DIRECTORY_SEPARATOR, strtolower($class_name)) . '.php';

return self::getFilePath( $filename,$return );
}

/**
* 载入指定类的定义文件,如果载入失败抛出异常
*
* @param string $class_name 要载入的类
* @param boolean $throw_exception 找不到指定类时是否抛出异常
*/
static function loadClass($class_name, $throw_exception = true)
{
if (class_exists($class_name, false) || interface_exists($class_name, false))
return;

$fileExists = false;

$filename = self::getClassFile($class_name,false);

if ($filename){
$fileExists = true;
require_once $filename;
if (class_exists($class_name, false) || interface_exists($class_name, false)) { return; }
}

if ($throw_exception)
{
throw new Core_Exception_ExpectedClass($class_name, $filename, $fileExists);
}
}

/**
* 添加一个类查找规则回调函数,要求规则匹配成功则返回类路径名称
*
* 诸如: modulescontactcontrollersdefault.php
* 失败返回false
*
* @param callback $callback
*/
static function addLocateRule($callback){
if (is_callable($callback)) {
$key = Core_AppUtils::callbackToString($callback);
if (!isset(self::$_locate_rules[$key]))
self::$_locate_rules[$key] = $callback;
}
}

/**
* 用于 的类自动载入,不需要由开发者调用
*
* @param string $class_name
* @access private
*/
static function autoload($class_name)
{
// 因为 php5.2.x spl_autoload 对应的方法中不能 throw 异常
// https://bugs.php.net/bug.php?id=45656
self::loadClass($class_name, false);
}

/**
* 注册或取消注册一个自动类载入方法
*
* @param boolean $enabled 启用或禁用该服务
*/
static function register($enabled = true)
{
static $registered = false;

if (!function_exists('spl_autoload_register'))
{
exit('spl_autoload does not exist in this PHP installation.');
}

$registered = $enabled ? ( $registered ? true : spl_autoload_register(array('Core_Autoloader', 'autoload')) )
: !spl_autoload_unregister(array('Core_Autoloader', 'autoload'));
}

/**
* 按照 命名规则,搜索文件
*
* 命名规则就是文件名中的“_”替换为目录分隔符。
*
* @param string $filename
* @param boolean $return 指示是否直接返回处理后的文件名,而不判断文件是否存在
*
* @return string
*/
static function getFilePath($filename, $return = false)
{
// patch: 2012-03-20 10:16:27 绝对路径出现 _ 也会被分割成 路径分隔符的 bug
if (is_readable($filename)) return $filename;

$filename = str_replace('_', DIRECTORY_SEPARATOR, $filename);

$filename = DIRECTORY_SEPARATOR == '/' ? str_replace('\', DIRECTORY_SEPARATOR, $filename) : str_replace('/', DIRECTORY_SEPARATOR, $filename);

if (strtolower(substr($filename, -4)) != '.php') {
$filename .= '.php';
}

// 首先搜索当前目录
if (is_file($filename)) { return $filename; }

foreach (self::$_class_path as $dir)
{
$path = $dir . DIRECTORY_SEPARATOR . $filename ;
if (is_file($path)) { return $path; }
}

if ($return) { return $filename; }
return false;
}

/**
* 载入指定的文件
*
* $filename 参数中的 “_” 将被替换为目录
*
* @param string $className
* @param boolean $loadOnce 指定为 true 时,等同于 require_once
*
* @return boolean
*/
static function loadFile($filename, $loadOnce = false)
{
static $is_loaded = array();

$path = self::getFilePath($filename);
if ($path != '') {
if (isset($is_loaded[$path]) && $loadOnce) { return true; }
$is_loaded[$path] = true;
if ($loadOnce) {
return require_once($path);
} else {
return require($path);
}
}
throw new Core_Exception_ExpectedFile($filename);
}
}

使用方法:

 Core_Autoloader::register(true);

/**
* 定位Core命名空间中的类文件路径
*
* @param string $class_name
* @return string
*/
function core_locate_class($class_name){
if (!preg_match('/^Core_/i',$class_name))
return false;
$_ = preg_replace('/^Core_/i','',$class_name);
if (empty($_)) return false;

$_ = Core_AppUtils::normalize(strtolower($_),'_');
return COREPATH . '/classes/' . implode('/',$_) . '.php';
}
Core_Autoloader::addLocateRule('core_locate_class');

这个规则支持传入多个

 /**
* 定位pkg 命名空间中的类文件路径
*
* @param string $class_name
* @return string
*/
function pkg_locate_class($class_name){
if (!preg_match('/^Pkg_/i',$class_name))
return false;
$_ = preg_replace('/^Pkg_/i','',$class_name);

if (empty($_)) return false;

$_ = Core_AppUtils::normalize(strtolower($_),'_');
return PKGPATH . '/' . implode('/',$_) . '.php';
}

/**
* 定位app库中的类文件路径
*
* @param string $class_name
* @return string
*/
function app_locate_class($class_name){
if (!preg_match('/^App_/i',$class_name))
return false;
$_ = preg_replace('/^App_/i','',$class_name);

if (empty($_)) return false;

$_ = Core_AppUtils::normalize(strtolower($_),'_');
return APPPATH . '/classes/' . implode('/',$_) . '.php';
}

当类在未找到时就会自动 按这些条件进行查找 加载 :-)

晚风撩人 2017-09-26 3 楼

我自己的框架里这么写的:

 class Loader{
/**
* 构造函数
*/
public function __construct(){
spl_autoload_register( array(__CLASS__, 'autoload') );
}

/**
* 自动加载
* @param String $class
*/
protected static function autoload($class){
if (class_exists($class, false) || interface_exists($class, false)) {
return true;
}
$class = trim($class, '\');

$file = str_replace('_', DS, $class) . '.php';

require($file);
return true;
}
}

甜柠檬 2017-09-19 2 楼

用php的__autoload方法

例:

<?php
// PHP5 Used __autoload function
$obj_A = new clsA(); // in "cls" directory!
$obj_B = new clsB(); // in "cls/cls" directory!
function __autoload($className){
if(strtolowwer($className) == "clsb"){
require_once "cls/cls/$className.php";
}else{
include_once "cls/$className.php";
}
}
?>

瑾兮 2017-08-28 1 楼

使用 spl_autoload_register() 来注册自动加载函数。

然后根据自己的命名来加载指定的文件:

之前写的一个贴出来,供参考:

spl_autoload_register(array('Mvc','autoload'));

/**
* 自动加载类函数
*
* @param string $class 需要引入类的名称
* @access public
* @returns void
*/
static public function autoload($class,$dirName = '') {

$path = '';
$className = ucfirst($class);
if(strpos($className,"Core_") !== false) {
$path = FRAMEWORK.'core'.DS.strtolower(str_replace('Core_','',$className)).EXT;
}else if(strpos($className,"Controller") !== false) {
$dir = self :: getTemplateDir() ? self :: getTemplateDir() .DS :'';
$path = APP_DIR . 'controller' .DS. $dir . chr(ord($className{0})+32) . substr($className ,1).EXT;
}else if(strpos($className,"Model") !== false) {
$dir = self :: getTemplateDir() ? self :: getTemplateDir() .DS :'';
$dirName = !empty($dirName) ? $dirName. DS : '';
$path = APP_DIR . 'model' .DS. $dir . $dirName . chr(ord($className{0})+32) . substr($className ,1).EXT;
}else if(strpos($className,"Lib") !== false) {
$path = FRAMEWORK.'lib'.DS.strtolower(str_replace('Lib_','',$className)).EXT;
}else if ($className === 'Constant') {
$path = APP_DIR.'config'.DS.'constant'.EXT;
}else {
self::fatalError("类 '" .$class . "' 无法加载,请检查文件命名是否规范,或该文件不在自动加载的范围内");
}
file_exists($path) || self ::fatalError($path . " 文件不存在");
require_once($path);

}