php 通过反射技术,把类中的方法转换为速查手册文档

php 通过反射技术,把类中的方法转换为速查手册文档

<?php
// 文件:class2handbook.php
/**
 * php 通过反射技术,把类中的方法转换为速查手册文档。
 * 功能:遍历目录中的类文件,通过类的反射技术,把类的所有方法输出到速查手册文档文件
 * 注意:一次只能同时处理一个目录,而且类的命名空间要相同
 */
// 类名
$className = 'CommonHelper';
// 类的命名空间
$nameSpace = 'MyApp\\Lib\\';
// 输出保存的文件
$toFilePath = './handbook_temp.md';
// 是否批量处理
$isBatch = true;
if ($isBatch) {
    $files = fastScanDir('../../src/lib/');
    foreach ($files as $filename => $fileinfo) {
        $className = basename($filename, '.php');
        include '../../src/lib/' . $className . '.php';
        makeHandbook($className, $nameSpace, $toFilePath);
    }
} else {
    include '../../src/lib/' . $className . '.php';
    makeHandbook($className, $nameSpace, $toFilePath);
}

/**
 * 反射类对象并输出所有方法到速查手册文件
 * @param string $className 类名
 * @param string $nameSpace 命令空间
 * @param string $toFilePath 输出的文件路径
 * @return void
 */
function makeHandbook($className, $nameSpace, $toFilePath)
{
    $docArr = [];
    $objClass = new ReflectionClass($nameSpace . $className);
    $docArr[] = $className . ' ' . parseComment($objClass->getDocComment());  // 获取类的注释文档
    $docArr[] = '命名空间: ' . $objClass->getNamespaceName();  // 获取类的命名空间
    $docArr[] = '~~~php';
    $methods = $objClass->getMethods();
    foreach ($methods as $objMethod) {
        $docArr[] = '// ' . parseComment($objMethod->getDocComment());  // 获取方法的注释文档
        $protected = '';
        if ($objMethod->isPrivate()) {
            $protected = 'private ';
        }
        if ($objMethod->isProtected()) {
            $protected = 'protected ';
        }
        if ($objMethod->isPublic()) {
            $protected = 'public ';
        }
        if ($objMethod->isStatic()) {
            $docArr[] = $protected . $className . '::' . $objMethod->getName() . '(' . parseParameters($objMethod) . ')';
        } else {
            $docArr[] =  $protected . '$instance->' . $objMethod->getName() . '(' . parseParameters($objMethod) . ')';
        }
    }
    $docArr[] = '~~~';
    $docArr[] = ''; // 换行
    $docArr[] = ''; // 换行
    // 自动创建目录
    $toDir = dirname($toFilePath);
    if (!is_dir($toDir)) {
        mkdir($toDir);
    }
    $content = implode(PHP_EOL, $docArr);
    file_put_contents($toFilePath, $content, FILE_APPEND);
    echo $className, ' done.', PHP_EOL;
}

/**
 * 解析注释文档,提取第一行的内容
 * @param string $comment 注释,风格是多行注释(\/** ... *\/)
 * @return string 返回第一行注释内容
 */
function parseComment($comment)
{
    $comments = explode(PHP_EOL, $comment);
    $comment = '';
    if (isset($comments[1])) {
        $comment = trim(trim(trim($comments[1]), '*'));
    }
    return $comment;
}
/**
 * 解析类的方法的参数列表
 * @param \ReflectionMethod 方法反射类
 * @return string 返回方法参数的字符串
 */
function parseParameters($objMethod)
{
    $paramsArr = [];
    $objParams = $objMethod->getParameters();
    foreach ($objParams as $objParam) {
        $paramStr = '$' . $objParam->getName();
        // $objParam->isDefaultValueConstant() // 默认值是否是枚举类型 method($opts=Foo::OPTION_MULTIGET);
        // 是否有默认值
        if ($objParam->isDefaultValueAvailable()) {
            $defaultValue =   $objParam->getDefaultValue();
            switch (gettype($defaultValue)) {
                case 'string':
                    $paramStr .= sprintf(" = '%s'", $defaultValue);
                    break;
                case 'array':
                    $paramStr .= ' = ' . varExport($defaultValue);
                    break;
                case 'NULL':
                    $paramStr .= ' = null';
                    break;
                case 'boolean':
                    $paramStr .= ' = ' . var_export($defaultValue, true);
                    break;
                default: // integer, float, object
                    $paramStr .= ' = ' .  $defaultValue;
                    break;
            }
        }
        $defaultValue = $objParam->isOptional();
        $paramsArr[] = $paramStr;
    }
    return implode(', ', $paramsArr);
}

/**
 * var_export() 方法的现代风格版
 * 说明:原始版:array(), 现代版:[]
 * @param mixed $var
 * @param string $indent 缩进内容,默认是空格
 * @param boolean $isCompact 是否紧凑模式,即数组是否换行
 * @return string
 */
function varExport($var, $indent = '', $isCompact = true)
{
    switch (gettype($var)) {
        case "string":
            return '\'' . addcslashes($var, "\\\$\"\r\n\t\v\f") . '\'';
        case "array":
            if (count($var) == 0) {
                return '[]';
            }
            $newLine = $isCompact ? '' : "\n";
            $itemSpace = $isCompact ? "$indent " : "$indent    ";
            $indexed = array_keys($var) === range(0, count($var) - 1);
            $r = [];
            foreach ($var as $key => $value) {
                $r[] = $itemSpace . ($indexed ? "" : varExport($key) . " => ") . varExport($value, $itemSpace);
            }
            return "[$newLine" . implode(",$newLine", $r) . "$newLine" . $indent . "]";
        case "boolean":
            return $var ? "TRUE" : "FALSE";
        default:
            return var_export($var, true);
    }
}

/**
 * PHP 高效遍历文件夹(大量文件不会卡死,带文件名排序功能)
 * @param string $path 目录路径
 * @param integer $level 目录深度层级
 * @param boolean $showfile 是否显示文件(否则只遍历显示目录)
 * @param array $skips 要忽略的文件路径集合
 * @param integer $deepth 扫描深度
 */
function fastScanDir($path = './', $level = 0, $showfile = true, $skips = array(), $deepth = 0)
{
    if (!file_exists($path) || ($deepth && $level > $deepth)) {
        return array();
    }
    $path = str_replace('//', '/', $path . '/');
    $file = new \FilesystemIterator($path);
    $filename = '';
    $icon = ''; // 树形层级图形
    if ($level > 0) {
        $icon = ('|' . str_repeat('--', $level));
    }
    $outarr = array();
    foreach ($file as $fileinfo) {
        $filename = iconv('GBK', 'utf-8', $fileinfo->getFilename()); // 解决中文乱码
        $filepath = $path . $filename;
        if ($fileinfo->isDir()) {
            if (!($skips && in_array($filepath . '/', $skips))) {
                $outarr[$filename] = array('path' => $filepath, 'type' => 'dir', 'icon' => $icon);
                $outarr[$filename]['children'] = fastScanDir($filepath, $level + 1, $showfile);
            }
            continue;
        }
        if ($showfile && !($skips && !in_array($filepath, $skips))) {
            $outarr[$filename] = array('path' => $filepath, 'type' => 'file', 'icon' => $icon);
        }
    }
    if ($outarr) {
        ksort($outarr);
    }
    return $outarr;
}

posted on 2021-02-25 10:17  sochishun  阅读(59)  评论(0编辑  收藏  举报