因appfront/config/main.php中87行prefix处包括匿名函数,故index-merge-config.php不能完成。

问题咨询 · phoenix · 于 7年前 发布 · 2350 次阅读

为避嫌,分享一点小知识吧。 我把appfront/web/index-merge-config.php的toPhpCode函数给拆解掉了。 拆解本为了理解,分享出来就可能是在害人了。但因太菜,无物出手,请作者原谅。 拆解原则如下: 一、一个函数尽量只做一件事。 二、尽量少用else避免太深层的嵌套。

//单个制表符用几个空格来表示
const TAB_DEFAULT_SPACES = 4;
/**
 * 获取某维的缩进空格字符串
 * @param $dimensional 维数,即当前在数组的第几层。
 * @return string 返回当前层的缩进空格的字符串
 */
function obtainSpaces($dimensional)
{
    $spaceNumber = $dimensional * TAB_DEFAULT_SPACES;
    $spaceStr = '';
    for ($index = 0; $index < $spaceNumber; $index++) {
        $spaceStr .= ' ';
    }
    return $spaceStr;
}

/**
 * @param $val 数组的键值对里的值(如果不是数组的时候的)
 * @return string 返回相应类型所对应的字符串
 */
function formatNotArray($val)
{
    if (is_string($val)) {
        return "'".$val."'";
    }
    if (is_bool($val)) {
        return $val? 'true' : 'false';
    }
    return is_null($val)? "''" : $val;
}

/**
 * 格式化数组(格式化成字符串)
 * @param $arr 要格式化的数组
 * @param $dimensional 维度,即当前数组处于被嵌套在第几层中
 * @param $pre_sapces_str 上一维度的输出空格字符串
 * @param $curr_spaces_str 当前维度的输出空格字符串
 * @return string 数组格式化后所得字符串
 */
function formatArray($arr,$dimensional,$pre_sapces_str,$curr_spaces_str)
{
    $str = PHP_EOL.$pre_sapces_str.'['.PHP_EOL;
    $index = 1;
    foreach ($arr as $k => $v) {
        1 != $index && $str .= PHP_EOL;
        $index = -1;
        $key = is_string($k)? "'".$k."'" : $k;
        $value = '';
        if (is_array($v)) {
            $value = toPhpCode($v, $dimensional);
        }else {
            $value = formatNotArray($v);
        }
        $str .= $curr_spaces_str.$key.'=>'.$value.',';
    }
    $str .= PHP_EOL.$pre_sapces_str.']';
    return $str;

}

/**
 * 转成php代码
 * @param $arr 要转的数组
 * @param int $dimensional 维度,即当前数组处于被嵌套在第几层中
 * @return string 格式化后所得字符串
 */
function toPhpCode($arr, $dimensional = 0)
{
    if (!is_array($arr)) {
        return formatNotArray($arr);
    }
    $pre_sapces_str = obtainSpaces($dimensional);
    $dimensional++;
    $curr_spaces_str = obtainSpaces($dimensional);
    return formatArray($arr,$dimensional,$pre_sapces_str,$curr_spaces_str);
}
共收到 12 条回复 问题提问
Fecmall#17年前 0 个赞

多谢您的用心的建议,并把代码贴出来分享,多谢,我先细看一下您的代码。

我写的代码的确存在问题,对于配置文件中的匿名函数不能更好的支持(fecshop目前没有匿名函数,所以也没有考虑这个)。

讨论技术知识,不用避嫌啊,直来直去就很好,我分享出来fecshop的代码,大家提意见,也可以帮助我提升技能,这样很好啊,感谢!

你是不是经常写shell脚本

1 != $index && $str .= PHP_EOL;

这行代码好有shell脚本的感觉。

Fecmall#27年前 0 个赞

你是否有办法,将函数的内容,以字符串的方式输出,譬如:

$var = function ($message) {
                        return $message;
                    };

php 有没有函数可以把这个函数代码打印出来?

在配置中会存在function,譬如:

'targets' => [
                'file' =>[
                    //'levels' => ['trace'],
                    'categories' => ['fecshop_debug'],
                    'class' => 'yii\log\FileTarget',
                    # 当 yii\log\Logger 对象刷新日志消息到 log targets 的时候,它们并 不能立即获取导出的消息。相反,消息导出仅仅在一个日志目标累积了一定数量的过滤消息的时候才会发生。你可以通过配置 个别的 log targets 的 yii\log\Target::exportInterval 属性来 自定义这个数量,就像下面这样:
                    'exportInterval' => 1,
                    # 输出文件
                    'logFile' => '@appfront/runtime/fecshop_logs/fecshop_debug.log',
                    # 你可以通过配置 yii\log\Target::prefix 的属性来自定义格式,这个属性是一个PHP可调用体返回的自定义消息前缀
                    'prefix' => function ($message) {
                        return $message;
                    },
                    # 除了消息前缀以外,日志目标也可以追加一些上下文信息到每组日志消息中。 默认情况下,这些全局的PHP变量的值被包含在:$_GET, $_POST, $_FILES, $_COOKIE,$_SESSION 和 $_SERVER 中。 你可以通过配置 yii\log\Target::logVars 属性适应这个行为,这个属性是你想要通过日志目标包含的全局变量名称。 举个例子,下面的日志目标配置指明了只有 $_SERVER 变量的值将被追加到日志消息中。
                    # 你可以将 logVars 配置成一个空数组来完全禁止上下文信息包含。或者假如你想要实现你自己提供上下文信息的方式, 你可以重写 yii\log\Target::getContextMessage() 方法。
                     'logVars' => [],
                ],
            ],

上面代码中的这个部分就是一个function

'prefix' => function ($message) {
                        return $message;
                    },
Fecmall#37年前 1 个赞

上面的问题,已经解决,参看: https://stackoverflow.com/questions/7026690/reconstruct-get-code-of-php-function

在您的函数上面,进行了更改,将配置中出现函数的部分进行了处理,最终代码如下:

//单个制表符用几个空格来表示
const TAB_DEFAULT_SPACES = 4;
/**
 * 获取某维的缩进空格字符串
 * @param $dimensional 维数,即当前在数组的第几层。
 * @return string 返回当前层的缩进空格的字符串
 */
function obtainSpaces($dimensional)
{
    $spaceNumber = $dimensional * TAB_DEFAULT_SPACES;
    $spaceStr = '';
    for ($index = 0; $index < $spaceNumber; $index++) {
        $spaceStr .= ' ';
    }
    return $spaceStr;
}

/**
 * @param $val 数组的键值对里的值(如果不是数组的时候的)
 * @return string 返回相应类型所对应的字符串
 */
function formatNotArray($val)
{
    if (is_string($val)) {
        return "'".$val."'";
    }
    if (is_bool($val)) {
        return $val? 'true' : 'false';
    }
    if (is_object($val)) {
        $post_log = '';
        ob_start();
        ob_implicit_flush(false);
        $func = new ReflectionFunction($val);
        $filename = $func->getFileName();
        $start_line = $func->getStartLine() - 1; // it's actually - 1, otherwise you wont get the function() block
        $end_line = $func->getEndLine();
        $length = $end_line - $start_line;
        $source = file($filename);
        $body = implode("", array_slice($source, $start_line, $length));
        echo $body;
        $post_log = ob_get_clean();
        return $post_log;
    }
    //if()
    return is_null($val)? "''" : $val;
}



/**
 * 格式化数组(格式化成字符串)
 * @param $arr 要格式化的数组
 * @param $dimensional 维度,即当前数组处于被嵌套在第几层中
 * @param $pre_sapces_str 上一维度的输出空格字符串
 * @param $curr_spaces_str 当前维度的输出空格字符串
 * @return string 数组格式化后所得字符串
 */
function formatArray($arr,$dimensional,$pre_sapces_str,$curr_spaces_str)
{
    $str = PHP_EOL.$pre_sapces_str.'['.PHP_EOL;
    $index = 1;
    foreach ($arr as $k => $v) {
        1 != $index && $str .= PHP_EOL;
        $index = -1;
        $key = is_string($k)? "'".$k."'" : $k;
        $value = '';
        if (is_array($v)) {
            $value = toPhpCode($v, $dimensional);
            $str .= $curr_spaces_str.$key.'=>'.$value.',';
        }else if(is_object($v)) {
            $value = formatNotArray($v);
            $str .= $curr_spaces_str.$value;
        }else {
            $value = formatNotArray($v);
            $str .= $curr_spaces_str.$key.'=>'.$value.',';
        }
        //$str .= $curr_spaces_str.$key.'=>'.$value.',';
    }
    $str .= PHP_EOL.$pre_sapces_str.']';
    return $str;

}

/**
 * 转成php代码
 * @param $arr 要转的数组
 * @param int $dimensional 维度,即当前数组处于被嵌套在第几层中
 * @return string 格式化后所得字符串
 */
function toPhpCode($arr, $dimensional = 0)
{
    if (!is_array($arr)) {
        return formatNotArray($arr);
    }
    $pre_sapces_str = obtainSpaces($dimensional);
    $dimensional++;
    $curr_spaces_str = obtainSpaces($dimensional);
    return formatArray($arr,$dimensional,$pre_sapces_str,$curr_spaces_str);
}


多谢您的分享和帮助

phoenix#47年前 0 个赞

非常感谢作者的回复和解答。反射用得好。

phoenix#57年前 0 个赞

出于强迫症,还是稍微做了整理。

//单个制表符用几个空格来表示
const TAB_DEFAULT_SPACES = 4;
/**
 * 获取某维的缩进空格字符串
 * @param $dimensional 维数,即当前在数组的第几层。
 * @return string 返回当前层的缩进空格的字符串
 */
function obtainSpaces($dimensional)
{
    $spaceNumber = $dimensional * TAB_DEFAULT_SPACES;
    $spaceStr = '';
    for ($index = 0; $index < $spaceNumber; $index++) {
        $spaceStr .= ' ';
    }
    return $spaceStr;
}

/**
 * 格式化字符串和其它非引用类型
 * @param $val 数组的键值对里的值
 * @return string 返回相应类型所对应的字符串
 */
function formatStringAndOther($val)
{
    if (is_string($val)) {
        return "'".$val."'";
    }
    if (is_bool($val)) {
        return $val? 'true' : 'false';
    }
    return is_null($val)? "''" : $val;
}

/**
 * 用ReflectionFunction来获取闭环对象所在源文件的一些信息
 * 再根据信息得到相应代码并打印到缓存中,再从缓存中返回字符串
 * @param $val 数组中键值对里的值,即要反射出原代码的闭环对象。
 * @return string 返回闭环对象对应的代码
 */
function formatClosureObject($val)
{
    $code_str = '';
    ob_start();
    ob_implicit_flush(false);
    $func = new ReflectionFunction($val);
    $filename = $func->getFileName();
    $start_line = $func->getStartLine(); //作者原来在这里“-1”很灵巧。但为可读性好一点改到下面的"+1"和"-1"了。
    $end_line = $func->getEndLine();
    $length = $end_line - $start_line + 1;
    $source = file($filename);
    $code = implode("", array_slice($source, $start_line - 1, $length));//file转成数组后行数从零开始故减一
    echo $code;
    $code_str = ob_get_clean();
    return $code_str;
}

/**
 * 格式化数组(格式化成字符串)
 * @param $arr 要格式化的数组
 * @param $dimensional 维度,即当前数组处于被嵌套在第几层中
 * @param $pre_sapces_str 上一维度的输出空格字符串
 * @param $curr_spaces_str 当前维度的输出空格字符串
 * @return string 数组格式化后所得字符串
 */
function formatArray($arr,$dimensional,$pre_sapces_str,$curr_spaces_str)
{
    $str = PHP_EOL.$pre_sapces_str.'['.PHP_EOL;
    $eol_flag = 1;
    foreach ($arr as $k => $v) {
        1 != $eol_flag && $str .= PHP_EOL;
        $eol_flag = -1;
        $key = is_string($k) ? "'" . $k . "'" : $k;
        $value = '';
        if (is_object($v)) {
            $value = formatClosureObject($v);
            $str .= $value;
            $eol_flag = 1;
            continue;
        }
        if (is_array($v)) {
            $value = toPhpCode($v, $dimensional);
        }else{
            $value = formatStringAndOther($v);
        }
        $str .= $curr_spaces_str . $key . '=>' . $value . ',';
    }
    $str .= PHP_EOL.$pre_sapces_str.']';
    return $str;
}

/**
 * 转成php代码
 * @param $arr 要转的数组
 * @param int $dimensional 维度,即当前数组处于被嵌套在第几层中
 * @return string 格式化后所得字符串
 */
function toPhpCode($arr, $dimensional = 0)
{
    if (!is_array($arr)) {
        return formatStringAndOther($arr);
    }
    $pre_sapces_str = obtainSpaces($dimensional);
    $dimensional++;
    $curr_spaces_str = obtainSpaces($dimensional);
    return formatArray($arr,$dimensional,$pre_sapces_str,$curr_spaces_str);
}

Fecmall#67年前 0 个赞

多谢,你测试过了吧?测试过了,我明天找时间直接复制上去

Fecmall#77年前 0 个赞

你在这个Q群里面把? 186604851 Q加我下好友,多谢

phoenix#87年前 0 个赞

测试过的,可以用的。在Q群里的。好的。

phoenix#107年前 0 个赞

很荣幸。不过写成yappy2000的整理了。

Fecmall#117年前 0 个赞

不好意思,看错了,当时回了几个帖子。

提交的历史没法改了,不好意思,我在代码里面加下注释,加上你的名字,重新提交下

添加回复 (需要登录)
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册
Your Site Analytics