在github上很多项目都不会告诉你如何include或require他们的项目,有的项目会提供一个autoload.php文件直接引用即可(如Predis),有的项目什么也不会给,甚至在README中都不会给出require的代码(如Gaufrette)。毕竟国外的程序员都已经习以为常,使用autoload来包含项目非常容易。
下面,以自己写的一个小项目为例循序渐进讲解一下如果autoload项目文件。
主要项目文件介绍:
IpWatch.class.php:类文件,IpWatch是主要用到的类。
FileCache.class.php:类文件,FileCache在IpWatch内部实例化。
RedisCache.class.php:类文件,RedisCache在IpWatch内部实例化。
其余的后面再说,传统方式使用只需要引用这三个文件即可使用本项目的所有功能,代码如下。
传统:<?php
include 'IpWatch.class.php';
include 'FileCache.class.php';
include 'RedisCache.class.php';
use Shuiguang\IpWatch;
use Shuiguang\FileCache;
use Shuiguang\RedisCache;
$file_config = array(
'interval' => 60, //最后一次请求到现在的间隔时间(s),如果大于此值则清除统计缓存
'mode' => 'file', //可选file(文件记录),redis(需安装redis扩展)
'type' => 'time', //可选number(数值记录),time(访问时间记录)
'file_dir' => 'ip', //缓存文件路径,建议放在/tmp目录下或定时清除
'prefix' => '', //缓存文件名前缀
'suffix' => '.ip', //缓存文件名后缀
);
$ipWatcher = Shuiguang\IpWatch::getInstance($file_config);
//允许单个IP单位时间内最大访问次数
$max_request = 10;
//获取当前IP访问次数
$current = $ipWatcher->get();
//超过这个次数则退出脚本
if($current >= $max_request)
{
die($current);
}else{
$add = $ipWatcher->incr();
}
echo 'ok, go on';
使用传统的include或require方式:当项目文件数较小的时候,多处逻辑代码引用了这3个文件,如果后来该项目增加了其他很多的类文件,需要修改所有的逻辑代码,非常不便。
如果使用__autoload来定义include规则自动include类文件将会非常轻松。
进阶:<?php
//自定义自动加载函数
function autoload($classname)
{
$dir = './';
if(is_file($dir.'/'.$classname.'.class.php'))
{
include $dir.'/'.$classname.'.class.php';
}else{
throw new Exception($dir.'/'.$classname.'.class.php not exists');
}
}
//注册自动加载函数
spl_autoload_register('autoload');
use Shuiguang\IpWatch;
use Shuiguang\FileCache;
use Shuiguang\RedisCache;
$file_config = array(
'interval' => 60, //最后一次请求到现在的间隔时间(s),如果大于此值则清除统计缓存
'mode' => 'file', //可选file(文件记录),redis(需安装redis扩展)
'type' => 'time', //可选number(数值记录),time(访问时间记录)
'file_dir' => 'ip', //缓存文件路径,建议放在/tmp目录下或定时清除
'prefix' => '', //缓存文件名前缀
'suffix' => '.ip', //缓存文件名后缀
);
$ipWatcher = Shuiguang\IpWatch::getInstance($file_config);
//允许单个IP单位时间内最大访问次数
$max_request = 10;
//获取当前IP访问次数
$current = $ipWatcher->get();
//超过这个次数则退出脚本
if($current >= $max_request)
{
die($current);
}else{
$add = $ipWatcher->incr();
}
echo 'ok, go on';
然而这样的方式并不是非常合适,一方面autoload函数将会作用于全局这样并不好,另一方面autoload函数中的.class.php文件路径是固定的,而且无法使用命名空间、子空间的优势。
从Predis项目中可以找到一个这样的类:Autoloader.php。(本项目中已经将类文件重命名为Autoloader.class.php)。
优化:<?php
/*
* This file is part of IpWatch.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
* IpWatch for php
* @author shuiguang
* @link https://github.com/shuiguang/IpWatch
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace Shuiguang;
class Autoloader
{
private $directory;
private $prefix;
private $prefixLength;
/**
* @param string $baseDirectory Base directory where the source files are located.
*/
public function __construct($baseDirectory = __DIR__)
{
$this->directory = $baseDirectory;
$this->prefix = __NAMESPACE__ . '\\';
$this->prefixLength = strlen($this->prefix);
}
/**
* Registers the autoloader class with the PHP SPL autoloader.
*
* @param bool $prepend Prepend the autoloader on the stack instead of appending it.
*/
public static function register($prepend = false)
{
spl_autoload_register(array(new self, 'autoload'), true, $prepend);
}
/**
* Loads a class from a file using its fully qualified name.
*
* @param string $className Fully qualified name of a class.
*/
public function autoload($className)
{
if (0 === strpos($className, $this->prefix)) {
$parts = explode('\\', substr($className, $this->prefixLength));
$filepath = $this->directory.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, $parts).'.class.php';
if (is_file($filepath)) {
require($filepath);
}
}
}
}
该类中主要使用了上一篇文章《PHP命名空间namespace使用》中介绍的__NAMESPACE__自动获取命名空间(文件夹名)和子命名空间(子文件夹名),然后通过autoload.php文件中的Shuiguang\Autoloader::register();进行注册。原理大致相同,但是实现方式非常优雅,所有的逻辑程序文件可引入autoload.php后直接使用即可,代码如下。<?php
/*
* This file is part of IpWatch.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
* IpWatch for php
* @author shuiguang
* @link https://github.com/shuiguang/IpWatch
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
require __DIR__ . '/src/Shuiguang/Autoloader.class.php';
Shuiguang\Autoloader::register();
逻辑代码如下:include 'autoload.php';
use代码
调用代码
如果以后需要添加类文件,放在src/Shuiguang下然后use即可,无需手动导入。
案例:
从github上下载最新版的Gaufrette,官方未给出任何自动加载的教程,需要我们自己实现。
解压之后,项目文件存在于Gaufrette-master\src\Gaufrette目录下,将predis中的Autoloader.php文件复制到Gaufrette-master\src\Gaufrette目录下,并且修改为namespace Gaufrette;<?php
namespace Gaufrette;
/**
* Implements a lightweight PSR-0 compliant autoloader for Predis.
*
* @author Eric Naeseth
* @author Daniele Alessandri
*/
class Autoloader
{
private $directory;
private $prefix;
private $prefixLength;
/**
* @param string $baseDirectory Base directory where the source files are located.
*/
public function __construct($baseDirectory = __DIR__)
{
$this->directory = $baseDirectory;
$this->prefix = __NAMESPACE__.'\\';
$this->prefixLength = strlen($this->prefix);
}
/**
* Registers the autoloader class with the PHP SPL autoloader.
*
* @param bool $prepend Prepend the autoloader on the stack instead of appending it.
*/
public static function register($prepend = false)
{
spl_autoload_register(array(new self(), 'autoload'), true, $prepend);
}
/**
* Loads a class from a file using its fully qualified name.
*
* @param string $className Fully qualified name of a class.
*/
public function autoload($className)
{
if (0 === strpos($className, $this->prefix)) {
$parts = explode('\\', substr($className, $this->prefixLength));
$filepath = $this->directory.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, $parts).'.php';
if (is_file($filepath)) {
require $filepath;
}
}
}
}
然后到Gaufrette-master目录建立一个autoload.php文件,该文件位置可任意放置,只需要保证require的路径正确即可。<?php
require __DIR__ . '/src/Gaufrette/Autoloader.php';
Gaufrette\Autoloader::register();
最后,到逻辑代码处引用这个autoload.php文件即可,例如。<?php
include 'autoload.php';
use Gaufrette\Filesystem;
use Gaufrette\Adapter\Local as LocalAdapter;
$adapter = new LocalAdapter(__DIR__);
$filesystem = new Filesystem($adapter);
$content = 'Hello I am the new content';
$filesystem->write('myFile.txt', $content);
完成引入该项目。
PS:外国人不喜欢使用.class.php作为类文件的后缀,通常直接使用.php文件名,其关键代码在Autoloader.php文件的这一行,怎么选取决于自己的习惯:$filepath = $this->directory.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, $parts).'.php';
案例下载:
随意转载~但请保留教程地址★