使用get_declared_class()只输出我声明的类,而不是PHP自动声明的类


use get_declared_class() to only ouput that classes I declared not the ones PHP does automatically

有点奇怪,但我想用像这样的东西从我声明的类中生成一个数组

foreach(get_declared_classes() as $class)
    $c[] = $class;

print_r($c);

唯一的问题是,我在加载的类上得到了类似的东西:

stdClass
Exception
ErrorException
Closure
DateTime
DateTimeZone
DateInterval
DatePeriod
LibXMLError
LogicException
BadFunctionCallException
BadMethodCallException
DomainException
InvalidArgumentException
LengthException
OutOfRangeException
RuntimeException
OutOfBoundsException
OverflowException
RangeException
UnderflowException
UnexpectedValueException
RecursiveIteratorIterator
IteratorIterator
{...}
SQLiteResult
SQLiteUnbuffered
SQLiteException
SQLite3
SQLite3Stmt
SQLite3Result
XMLReader
XMLWriter
XSLTProcessor
ZipArchive

是否存在只加载用户特定类而不加载系统加载类的函数?或者可能是限制foreach列出这些类的条件语句?

反射API可以检测类是否是内部的。ReflectionClass::isInternal检查类是否是内部的,而不是用户定义的:

$userDefinedClasses = array_filter(
    get_declared_classes(),
    function($className) {
        return !call_user_func(
            array(new ReflectionClass($className), 'isInternal')
        );
    }
);

上面的代码将检查并删除get_declared_classes返回的每个内部类,只留下用户定义的类。这样,您就不需要像本页其他地方建议的那样创建和维护一组内部类。

没有内置函数可以实现这一点,但您可以在声明任何内容之前使用get_declared_classes,并将其存储在全局变量中,比如$predefinedClasses。然后,在您需要使用的地方:

print_r(array_diff(get_declared_classes(), $predefinedClasses));

没有直接内置的可能性,但您可以执行以下操作:

  1. 在脚本开始时,调用get_declared_classes()并将其保存到类似$php_classes的变量中
  2. 加载完类后,再次调用get_declared_classes()并使用array_diff()过滤掉$php_classes,结果是您自己的类的列表。

    // start
    $php_classes = get_declared_classes();
    // ...
    // some code loading/declaring own classes
    // ...
    // later
    $my_classes = array_diff(get_declared_classes(), $php_classes);
    

这是我的解决方案,它确实有效,而且不会影响性能。这只提供了项目中定义的类,而没有其他类。确保在加载完所有类之后,尽可能晚地运行它。

/**
 * Get all classes from a project.
 *
 * Return an array containing all classes defined in a project.
 *
 * @param string $project_path
 * @return array
 */
function smk_get_classes_from_project( $project_path ){
    // Placeholder for final output
    $classes = array();
    // Get all classes
    $dc = get_declared_classes();
    // Loop
    foreach ($dc as $class) {
        $reflect = new 'ReflectionClass($class);
        // Get the path to the file where is defined this class.
        $filename = $reflect->getFileName();
        // Only user defined classes, exclude internal or classes added by PHP extensions.
        if( ! $reflect->isInternal() ){
            // Replace backslash with forward slash.
            $filename = str_replace(array(''''), array('/'), $filename);
            $project_path = str_replace(array(''''), array('/'), $project_path);
            // Remove the last slash. 
            // If last slash is present, some classes from root will not be included.
            // Probably there's an explication for this. I don't know...
            $project_path = rtrim( $project_path, '/' );
            // Add the class only if it is defined in `$project_path` dir.
            if( stripos( $filename, $project_path ) !== false ){
                $classes[] = $class;
            }
        }
    }
    return $classes;    
}

测试它。

本例假设项目具有以下路径:/srv/users/apps/my-project-name

echo '<pre>';
print_r( smk_get_classes_from_project( '/srv/users/apps/my-project-name' ) );
echo '</pre>';

另一种可能的方法是:

$a= get_declared_classes();
// All user-defined classes
print_r(array_slice(get_declared_classes(), count($a)));

@Gordon的回答非常好@Dmitry的解决方案也很好,但只有当你的类在不同的文件中,并且你包含了它们时,它才有效:

$predefinedClasses = get_declared_classes();
include('Myclass.php'); // This will show
class A {} // This will not show
print_r(array_diff(get_declared_classes(), $predefinedClasses));

然而,如果你的文件中除了包含的类之外还有其他类,如果你不想使用Reflection,我想出了一个(疯狂的)主意:

$predefined_classes = get_declared_classes();
declare(ticks=1) {
    include 'Myclass.php';
    class A {}
    print_r(array_diff(get_declared_classes(), $predefined_classes));
}