【发布时间】:2015-09-05 02:34:39
【问题描述】:
简短的问题
如何让 Autoloader 找到运行 PHP 测试所需的所有类?
问题详细
我想在 Eclipse 中自动加载我在 PHPUnit 中使用的类。我的目录结构如下。
Project (called yii-app)
protected
dirA
classA.php
dirB
classB.php
yii-1.1.14.f0fee9
Yii.php
tests
ClassATest.php
ClassBTest.php
bootstrap.php
Autoloader.php
我使用的是我找到的here 的bootstrap.php 和Autoloader.php,详情见下文。 classA 类没有使用 Yii 框架,ClassATest 中的测试运行顺利。 classB 类确实使用了 Yii 框架。第一行之一是:
Yii::import('application.<path into some directory>.*')
当我尝试在 ClassBTest.php 中运行测试时,出现以下错误。
Fatal error: Class 'Yii' not found in /Users/physicalattraction/git/yii-app/protected/dirB/classB.php on line 3
即使我注册了整个项目目录(包括子目录),也找不到 Class Yii,而它就在那里。我应该更改哪些内容才能使这些测试也运行?
注意
如果我尝试直接从终端运行测试,我也会遇到同样的问题,因此它与 Eclipse 无关。
$ ./composer/vendor/bin/phpunit --bootstrap=tests/bootstrap.php tests
PHPUnit 4.5.1 by Sebastian Bergmann and contributors.
Fatal error: Class 'Yii' not found in /Users/physicalattraction/git/yii-app/protected/dirB/classB.php on line 3
详情
Eclipse 中的 PHPUnit 设置
bootstrap.php
<?php
include_once('AutoLoader.php');
// Register the directory to your include files
Toolbox\Testing\AutoLoader::registerDirectory(__DIR__.'/../yii-1.1.14.f0fee9');
Toolbox\Testing\AutoLoader::registerDirectory(__DIR__.'/../protected');
?>
Autoloader.php
<?php
namespace Toolbox\Testing;
/**
* This class is an auto loader for use with vanilla PHP projects' testing environment. Use it in
* the bootstrap to register classes without having to use a framework (which you can, and should if
* it's a better solution for you) and without having to use includes everywhere.
*
* It assumes that the file path in relation to the namespace follows the PSR-0 standard.
*
* IMPORTANT NOTE: When just registering directories, the class has no ability to discern
* conflicting class names in different namespaces, which means that classes with the same name will
* override each other! Always use the registerNamespace()-method if possible!
*
* Inspired by Jess Telford's AutoLoader (http://jes.st/).
*
* @see http://jes.st/2011/phpunit-bootstrap-and-autoloading-classes/
* @see http://petermoulding.com/php/psr
* @see http://www.php-fig.org/psr/psr-0/
*
* @codeCoverageIgnore
*
* @category Toolbox
* @package Testing
*
* @author Helge Söderström <helge.soderstrom@schibsted.se>
*/
class AutoLoader {
/**
* An array keeping class names as key and their path as the value for classes registered with
* AutoLoader::registerNamespace().
*
* @var array
*/
protected static $namespaceClassNames = array();
/**
* An array keeping class names as key and their path as the value for classes registered with
* AutoLoader::registerDirectory().
*
* @var array
*/
protected static $directoryClassNames = array();
/**
* Store the filename (sans extension) & full path to all ".php" files found for a namespace.
* The parameter should contain the root namespace as the key and the directory as a value.
*
* @param string $namespace
* @param string $dirName
* @return void
*/
public static function registerNamespace($namespace, $dirName) {
$directoryContents = new \DirectoryIterator($dirName);
foreach($directoryContents as $file) {
if ($file->isDir() && !$file->isLink() && !$file->isDot()) {
$newNamespace = $namespace . "_" . $file->getFileName();
$newDirName = $dirName . "/" . $file->getFilename();
static::registerNamespace($newNamespace, $newDirName);
} elseif (substr($file->getFilename(), -4) === '.php') {
$className = substr($file->getFilename(), 0, -4);
$namespacedClassName = $namespace . "_" . $className;
$fileName = realpath($dirName) . "/" . $file->getFilename();
static::$namespaceClassNames[$namespacedClassName] = $fileName;
}
}
}
/**
* Store the filename (sans extension) & full path of all ".php" files found.
*
* NOTE: This method will not be able to differentiate the same class names in different
* namespaces and will therefore overwrite class names if multiple of the same name is
* found. If possible, use registerNamespace instead!
*
* @param string $dirName
* @return void
*/
public static function registerDirectory($dirName) {
$directoryContents = new \DirectoryIterator($dirName);
foreach ($directoryContents as $file) {
if ($file->isDir() && !$file->isLink() && !$file->isDot()) {
// Recurse into directories other than a few special ones.
static::registerDirectory($file->getPathname());
} elseif (substr($file->getFilename(), -4) === '.php') {
// Save the class name / path of a .php file found.
$className = substr($file->getFilename(), 0, -4);
AutoLoader::registerClass($className, $file->getPathname());
}
}
}
/**
* Caches a found class with the class name as key and its path as value for use when loading
* on the fly. The class is registered with its class name only, no namespace.
*
* @param string $className
* @param string $fileName
* @return void
*/
public static function registerClass($className, $fileName) {
AutoLoader::$directoryClassNames[$className] = $fileName;
}
/**
* Includes a found class in the runtime environment. Strips namespaces.
*
* @param string $className
* @return void
*/
public static function loadClass($className) {
// First, see if we've registered the entire namespace.
$namespacedClassName = str_replace('\\', '_', $className);
if (isset(static::$namespaceClassNames[$namespacedClassName])) {
require_once(static::$namespaceClassNames[$namespacedClassName]);
return;
}
// Nope. Have we registered it as a directory?
$psrDirectorySeparators = array('\\', '_');
foreach($psrDirectorySeparators as $separator) {
$separatorOccurrence = strrpos($className, $separator);
if($separatorOccurrence !== false) {
$className = substr($className, $separatorOccurrence + 1);
break;
}
}
if (isset(AutoLoader::$directoryClassNames[$className])) {
require_once(AutoLoader::$directoryClassNames[$className]);
}
}
}
// Register our AutoLoad class as the system auto loader.
spl_autoload_register(array('Toolbox\Testing\AutoLoader', 'loadClass'));
?>
【问题讨论】: