以下是一个实现psr-4规范的例子:
Closure Example
<code><span><?php</span><span>/**
* 一个具体项目实现的例子.
* 使用SPL注册了autoload函数之后,以下代码将触发autoload函数从
* /path/to/project/src/Baz/Qux.php 文件加载
* FooBarBazQux 类
* new FooBarBazQux;
*
*<span> @param</span> string $class The fully-qualified class name.
*<span> @return</span> void
*/</span>
spl_autoload_register(<span><span>function</span><span>(<span>$class</span>)</span> {</span><span>// 项目约定的命名空间前缀</span><span>$prefix</span> = <span>'Foo\Bar\'</span>;
<span>// 命名空间前缀的基础目录</span><span>$base_dir</span> = <span>__DIR__</span> . <span>'/src/'</span>;
<span>// 这个类是否使用了命名空间前缀?</span><span>$len</span> = strlen(<span>$prefix</span>);
<span>if</span> (strncmp(<span>$prefix</span>, <span>$class</span>, <span>$len</span>) !== <span>0</span>) {
<span>// 没有,尝试下个已注册的 autoloader</span><span>return</span>;
}
<span>// 获取相对类名(截取命名空间前缀后剩下的部分)</span><span>$relative_class</span> = substr(<span>$class</span>, <span>$len</span>);
<span>// 用base目录替换命名空间前缀;</span><span>// 用目录分隔符替换命名空间分隔符;</span><span>// 坠上 .php</span><span>$file</span> = <span>$base_dir</span> . str_replace(<span>'\'</span>, <span>'/'</span>, <span>$relative_class</span>) . <span>'.php'</span>;
<span>// 如果文件存在,加载文件。</span><span>if</span> (file_exists(<span>$file</span>)) {
<span>require</span><span>$file</span>;
}
});</code>Class Example
以下是一个处理多命名空间的类的例子。
<code><span><?php</span><span>namespace</span><span>Example</span>;
<span>/**
* 这个例子是一个针对 一个命名空间前缀对应多个base谬的通用实现。
*
* foo-bar 类的包分别在以下路径下...
*
* /path/to/packages/foo-bar/
* src/
* Baz.php # FooBarBaz
* Qux/
* Quux.php # FooBarQuxQuux
* tests/
* BazTest.php # FooBarBazTest
* Qux/
* QuuxTest.php # FooBarQuxQuuxTest
*
* ... 以下代码将类文件的路径添加到 FooBar命名空间前缀下。
*
* <span><?php</span>
* // 初始化 loader
* $loader = new ExamplePsr4AutoloaderClass;
*
* // 注册 autoloader
* $loader->register();
*
* // 为命名空间前缀注册base目录。
* $loader->addNamespace('FooBar', '/path/to/packages/foo-bar/src');
* $loader->addNamespace('FooBar', '/path/to/packages/foo-bar/tests');
*
* 下面的代码将触发 autoloader 尝试从
* /path/to/packages/foo-bar/src/Qux/Quux.php 加载
* FooBarQuxQuux 类:
*
* <span><?php</span>
* new FooBarQuxQuux;
*
* 以下代码触发autoloader尝试从
* /path/to/packages/foo-bar/tests/Qux/QuuxTest.php
* 加载FooBarQuxQuuxTest类 :
*
* <span><?php</span>
* new FooBarQuxQuuxTest;
*/</span><span><span>class</span><span>Psr4AutoloaderClass</span>
{</span><span>/**
* An associative array where the key is a namespace prefix and the value
* is an array of base directories for classes in that namespace.
*
*<span> @var</span> array
*/</span><span>protected</span><span>$prefixes</span> = <span>array</span>();
<span>/**
* Register loader with SPL autoloader stack.
*
*<span> @return</span> void
*/</span><span>public</span><span><span>function</span><span>register</span><span>()</span>
{</span>
spl_autoload_register(<span>array</span>(<span>$this</span>, <span>'loadClass'</span>));
}
<span>/**
* Adds a base directory for a namespace prefix.
*
*<span> @param</span> string $prefix The namespace prefix.
*<span> @param</span> string $base_dir A base directory for class files in the
* namespace.
*<span> @param</span> bool $prepend If true, prepend the base directory to the stack
* instead of appending it; this causes it to be searched first rather
* than last.
*<span> @return</span> void
*/</span><span>public</span><span><span>function</span><span>addNamespace</span><span>(<span>$prefix</span>, <span>$base_dir</span>, <span>$prepend</span> = false)</span>
{</span><span>// normalize namespace prefix</span><span>$prefix</span> = trim(<span>$prefix</span>, <span>'\'</span>) . <span>'\'</span>;
<span>// normalize the base directory with a trailing separator</span><span>$base_dir</span> = rtrim(<span>$base_dir</span>, DIRECTORY_SEPARATOR) . <span>'/'</span>;
<span>// initialize the namespace prefix array</span><span>if</span> (<span>isset</span>(<span>$this</span>->prefixes[<span>$prefix</span>]) === <span>false</span>) {
<span>$this</span>->prefixes[<span>$prefix</span>] = <span>array</span>();
}
<span>// retain the base directory for the namespace prefix</span><span>if</span> (<span>$prepend</span>) {
array_unshift(<span>$this</span>->prefixes[<span>$prefix</span>], <span>$base_dir</span>);
} <span>else</span> {
array_push(<span>$this</span>->prefixes[<span>$prefix</span>], <span>$base_dir</span>);
}
}
<span>/**
* Loads the class file for a given class name.
*
*<span> @param</span> string $class The fully-qualified class name.
*<span> @return</span> mixed The mapped file name on success, or boolean false on
* failure.
*/</span><span>public</span><span><span>function</span><span>loadClass</span><span>(<span>$class</span>)</span>
{</span><span>// the current namespace prefix</span><span>$prefix</span> = <span>$class</span>;
<span>// work backwards through the namespace names of the fully-qualified</span><span>// class name to find a mapped file name</span><span>while</span> (<span>false</span> !== <span>$pos</span> = strrpos(<span>$prefix</span>, <span>'\'</span>)) {
<span>// retain the trailing namespace separator in the prefix</span><span>$prefix</span> = substr(<span>$class</span>, <span>0</span>, <span>$pos</span> + <span>1</span>);
<span>// the rest is the relative class name</span><span>$relative_class</span> = substr(<span>$class</span>, <span>$pos</span> + <span>1</span>);
<span>// try to load a mapped file for the prefix and relative class</span><span>$mapped_file</span> = <span>$this</span>->loadMappedFile(<span>$prefix</span>, <span>$relative_class</span>);
<span>if</span> (<span>$mapped_file</span>) {
<span>return</span><span>$mapped_file</span>;
}
<span>// remove the trailing namespace separator for the next iteration</span><span>// of strrpos()</span><span>$prefix</span> = rtrim(<span>$prefix</span>, <span>'\'</span>);
}
<span>// never found a mapped file</span><span>return</span><span>false</span>;
}
<span>/**
* Load the mapped file for a namespace prefix and relative class.
*
*<span> @param</span> string $prefix The namespace prefix.
*<span> @param</span> string $relative_class The relative class name.
*<span> @return</span> mixed Boolean false if no mapped file can be loaded, or the
* name of the mapped file that was loaded.
*/</span><span>protected</span><span><span>function</span><span>loadMappedFile</span><span>(<span>$prefix</span>, <span>$relative_class</span>)</span>
{</span><span>// are there any base directories for this namespace prefix?</span><span>if</span> (<span>isset</span>(<span>$this</span>->prefixes[<span>$prefix</span>]) === <span>false</span>) {
<span>return</span><span>false</span>;
}
<span>// look through base directories for this namespace prefix</span><span>foreach</span> (<span>$this</span>->prefixes[<span>$prefix</span>] <span>as</span><span>$base_dir</span>) {
<span>// replace the namespace prefix with the base directory,</span><span>// replace namespace separators with directory separators</span><span>// in the relative class name, append with .php</span><span>$file</span> = <span>$base_dir</span>
. str_replace(<span>'\'</span>, <span>'/'</span>, <span>$relative_class</span>)
. <span>'.php'</span>;
<span>// if the mapped file exists, require it</span><span>if</span> (<span>$this</span>->requireFile(<span>$file</span>)) {
<span>// yes, we're done</span><span>return</span><span>$file</span>;
}
}
<span>// never found it</span><span>return</span><span>false</span>;
}
<span>/**
* If a file exists, require it from the file system.
*
*<span> @param</span> string $file The file to require.
*<span> @return</span> bool True if the file exists, false if not.
*/</span><span>protected</span><span><span>function</span><span>requireFile</span><span>(<span>$file</span>)</span>
{</span><span>if</span> (file_exists(<span>$file</span>)) {
<span>require</span><span>$file</span>;
<span>return</span><span>true</span>;
}
<span>return</span><span>false</span>;
}
}</code>Unit Tests
The following example is one way of unit testing the above class loader:
<code><span><?php</span><span>namespace</span><span>Example</span><span>Tests</span>;
<span><span>class</span><span>MockPsr4AutoloaderClass</span><span>extends</span><span>Psr4AutoloaderClass</span>
{</span><span>protected</span><span>$files</span> = <span>array</span>();
<span>public</span><span><span>function</span><span>setFiles</span><span>(array <span>$files</span>)</span>
{</span><span>$this</span>->files = <span>$files</span>;
}
<span>protected</span><span><span>function</span><span>requireFile</span><span>(<span>$file</span>)</span>
{</span><span>return</span> in_array(<span>$file</span>, <span>$this</span>->files);
}
}
<span><span>class</span><span>Psr4AutoloaderClassTest</span><span>extends</span> <span>PHPUnit_Framework_TestCase</span>
{</span><span>protected</span><span>$loader</span>;
<span>protected</span><span><span>function</span><span>setUp</span><span>()</span>
{</span><span>$this</span>->loader = <span>new</span> MockPsr4AutoloaderClass;
<span>$this</span>->loader->setFiles(<span>array</span>(
<span>'/vendor/foo.bar/src/ClassName.php'</span>,
<span>'/vendor/foo.bar/src/DoomClassName.php'</span>,
<span>'/vendor/foo.bar/tests/ClassNameTest.php'</span>,
<span>'/vendor/foo.bardoom/src/ClassName.php'</span>,
<span>'/vendor/foo.bar.baz.dib/src/ClassName.php'</span>,
<span>'/vendor/foo.bar.baz.dib.zim.gir/src/ClassName.php'</span>,
));
<span>$this</span>->loader->addNamespace(
<span>'FooBar'</span>,
<span>'/vendor/foo.bar/src'</span>
);
<span>$this</span>->loader->addNamespace(
<span>'FooBar'</span>,
<span>'/vendor/foo.bar/tests'</span>
);
<span>$this</span>->loader->addNamespace(
<span>'FooBarDoom'</span>,
<span>'/vendor/foo.bardoom/src'</span>
);
<span>$this</span>->loader->addNamespace(
<span>'FooBarBazDib'</span>,
<span>'/vendor/foo.bar.baz.dib/src'</span>
);
<span>$this</span>->loader->addNamespace(
<span>'FooBarBazDibZimGir'</span>,
<span>'/vendor/foo.bar.baz.dib.zim.gir/src'</span>
);
}
<span>public</span><span><span>function</span><span>testExistingFile</span><span>()</span>
{</span><span>$actual</span> = <span>$this</span>->loader->loadClass(<span>'FooBarClassName'</span>);
<span>$expect</span> = <span>'/vendor/foo.bar/src/ClassName.php'</span>;
<span>$this</span>->assertSame(<span>$expect</span>, <span>$actual</span>);
<span>$actual</span> = <span>$this</span>->loader->loadClass(<span>'FooBarClassNameTest'</span>);
<span>$expect</span> = <span>'/vendor/foo.bar/tests/ClassNameTest.php'</span>;
<span>$this</span>->assertSame(<span>$expect</span>, <span>$actual</span>);
}
<span>public</span><span><span>function</span><span>testMissingFile</span><span>()</span>
{</span><span>$actual</span> = <span>$this</span>->loader->loadClass(<span>'No_VendorNo_PackageNoClass'</span>);
<span>$this</span>->assertFalse(<span>$actual</span>);
}
<span>public</span><span><span>function</span><span>testDeepFile</span><span>()</span>
{</span><span>$actual</span> = <span>$this</span>->loader->loadClass(<span>'FooBarBazDibZimGirClassName'</span>);
<span>$expect</span> = <span>'/vendor/foo.bar.baz.dib.zim.gir/src/ClassName.php'</span>;
<span>$this</span>->assertSame(<span>$expect</span>, <span>$actual</span>);
}
<span>public</span><span><span>function</span><span>testConfusion</span><span>()</span>
{</span><span>$actual</span> = <span>$this</span>->loader->loadClass(<span>'FooBarDoomClassName'</span>);
<span>$expect</span> = <span>'/vendor/foo.bar/src/DoomClassName.php'</span>;
<span>$this</span>->assertSame(<span>$expect</span>, <span>$actual</span>);
<span>$actual</span> = <span>$this</span>->loader->loadClass(<span>'FooBarDoomClassName'</span>);
<span>$expect</span> = <span>'/vendor/foo.bardoom/src/ClassName.php'</span>;
<span>$this</span>->assertSame(<span>$expect</span>, <span>$actual</span>);
}
}</code>以上就介绍了PSR-4 实例,包括了方面的内容,希望对PHP教程有兴趣的朋友有所帮助。
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号