php 根据条件打印输出,方便调试

发布时间 2023-07-04 19:10:20作者: 心随所遇

laravel 核心代码调试起来,还是挺麻烦的,循环太多了。当从某个路由进去之后,进入到核心内部,断点打印的可能根据不是你认为的执行过程。为此,我想到了条件打印,跟用 ide debug 设置条件一样的思想。不过还是觉得打印更加直观一些吧。

代码很简单,一看就懂,不过多介绍了。

 

 

<?php

class debuger {

    protected $conditions = [];
    protected $file = '';
    public function __construct($value1 = true, $value2 = true)
    {
        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, );
        $this->file = str_replace(__DIR__ . DIRECTORY_SEPARATOR, '', $trace[1]['file']) .':'. $trace[1]['line'];
        $this->log = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'debug.txt';
        if(!isset($_ENV['debug_next_step'])){
            $_ENV['debug_next_step'] = 0;
        }
        if(func_num_args() == 1){
            $this->if($value1);
        }else{
            $this->eq($value1, $value2);
        }
    }

    public function dump(mixed ...$values)
    {
        ob_start();
        dump(...$values);
        echo preg_replace('/\/\/\s+helpers.php:\d+/', "// $this->file", ob_get_clean());
        return $this;
    }

    public function stop(mixed ...$values)
    {
        $this->dump(...$values);
        exit(1);
    }

    public function dd(mixed ...$values)
    {
        if($this->allIsTrue()){
            dd(...$values);
        }
    }

    public function du(mixed ...$values)
    {
        if(!$this->allIsTrue()) return $this;
        $this->dump(...$values);
        return $this;
    }

    public function if(mixed $value = true)
    {
        $this->conditions[] = boolval($value);
        return $this;
    }

    public function var(mixed ...$values)
    {
        if($this->allIsTrue()){
            var_dump(...$values);
        }
        return $this;
    }

    public function eq($value1 = true, $value2 = true, $strict = false)
    {
        if($strict){
            $this->conditions[] = $value1 === $value2;
        }else{
            $this->conditions[] = $value1 == $value2;
        }
        return $this;
    }

    public function empty($value = false)
    {
        $this->conditions[] =  empty($value);
        return $this;
    }

    public function full($value = true)
    {
        $this->conditions[] = !empty($value);
        return $this;
    }

    public function compare($value1, $symbol, $value2 = null)
    {
        if(func_num_args() == 2){
            $value2 = $symbol;
            $symbol = '=';
        }
        $this->conditions[] = eval("$value1 $symbol $value2");
        return $this;
    }


    public function true($value, $strict = false)
    {
        if($strict){
            $this->conditions[] = $value === true;
        }else{
            $this->conditions[] = $value == true;
        }
        return $this;
    }

    public function false($value, $strict = false)
    {
        if($strict){
            $this->conditions[] = $value === false;
        }else{
            $this->conditions[] = $value == false;
        }
        return $this;
    }

    public function null($value = null)
    {
        $this->conditions[] = is_null($value);
        return $this;
    }

    protected function allIsTrue()
    {
        return count($this->conditions) == count(array_filter($this->conditions));
    }

    public function exec($callback = null, ...$args)
    {
        if($this->allIsTrue()){
            if(is_callable($callback)){
                call_user_func($callback, ...$args);
            }else{
                $this->dd('$callback is not callable');
            }
        }
        return $this;
    }

    public function dir($value)
    {
        $this->conditions[] = is_dir($value);
        return $this;
    }


    public function next(int $value = 0)
    {
        if($this->allIsTrue()){
            $_ENV['debug_next_step'] = $value;
        }
        return $this;
    }


    public function prev(int $value = 0)
    {
        $this->conditions[] = $value == $_ENV['debug_next_step'];
        return $this;
    }

    public function here(string $value = '== debug here ==')
    {
        dd($value);
    }

    public function return($value, $default = null)
    {
        return $this->allIsTrue()? $value : $default;
    }

    public function trace()
    {
        if($this->allIsTrue()){
            $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
            $trace = array_reverse($trace);
            $html = '<table style="border-collapse:collapse;width: 100%;" >';
            foreach($trace as $key => $item){
                !isset($item['class']) && $item['class'] = '';
                !isset($item['type']) && $item['type'] = '';
                !isset($item['function']) && $item['function'] = '';
                $item['file'] = str_replace([__DIR__ . '/', 'vendor/', 'laravel/framework/src/', 'laravel/', '/'], ['', '', '', '', '\\'], $item['file']);
                $html .= "<tr><td style='border:1px solid #DDD;padding:4px;'>$key</td><td style='border:1px solid #DDD;padding:4px;'><td style='border:1px solid #DDD;padding:4px 30px 4px 4px;width:0px;'>{$item['file']}:{$item['line']}</td><td  style='border:1px solid #DDD;padding:4px;'>{$item['class']}{$item['type']}{$item['function']}()</td></tr>";
            }
            $html .= '</table>';
            echo $html;
        }
        return $this;
    }

    public function exit()
    {
        if($this->allIsTrue()) exit(1);
    }


    public static function unicode($string)
    {
        return preg_replace_callback('/\\\\u([0-9a-f]{4})/i', function($match) {
            return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE');
        }, $string);
    }

    public function format(mixed ...$args)
    {
        $cli = PHP_SAPI == 'cli' ? true : false;
        $content = $cli ? $this->file . PHP_EOL : '<pre style="margin-bottom:5px;background:#f3f3f4;padding:5px;border:1px solid #DDD;">文件: ' . $this->file . PHP_EOL . '<hr/>';
        foreach($args as $key => $data) {
            $append = [];
            if(is_bool($data)) {
                $content .= ($data ? '(bool) true' : '(bool) false') . PHP_EOL;
            }else if(is_null($data)) {
                $content .= '(null) null' . PHP_EOL;
            }else if($data === '') {
                $content .= '""' . PHP_EOL;
            }else if(is_array($data)){
                $content .= print_r($data, true);
            }else if(is_scalar($data) && !function_exists($data) && !class_exists($data, false)){
                $content .= self::unicode($data) . PHP_EOL;
            }
            if(is_string($data) && function_exists($data)){
                $object = new \ReflectionFunction($data);
                $content .= print_r(['Type' => 'Function', 'Name' => $data, 'Namespace' => $object->getNamespaceName(), 'File' => $object->getFilename()], true);
            }
            if(is_object($data) || (is_string($data) && class_exists($data, false))) {
                $message = '';
                if(is_object($data)) {
                    if($data instanceof \Exception) {
                        $file = $data->getFile() . ':' . $data->getLine();
                        $message = $data->getMessage() . ' (' . $data->getCode() . ')';
                    }else if($data instanceof \think\Model || (is_array($data) && current($data) instanceof \think\Model)){
                        $append['Collect'] = collection($data)->toArray();
                    }else if(method_exists($data, 'toArray')) {
                        $append['ToArray'] = $data->toArray();
                    }else if(method_exists($data, '__toString')) {
                        $append['ToString'] = $data->__toString();
                    }
                    $name = get_class($data);
                    $fields = get_object_vars($data);
                }else {
                    $name = $data;
                    $fields = get_class_vars($data);
                }
                $methods = get_class_methods($data);
                $object = new \ReflectionClass($data);
                if(!isset($file)) {
                    $file = $object->getFilename();
                }
                $content .= print_r(array('Type' => (is_object($data)? 'Object' : 'Class'),  (is_object($data)? 'Class' : 'Name') => $name, 'Namespace' => $object->getNamespaceName(), 'Exception' => $message, 'File' => $file, 'Attribute ' => $fields, 'Data' => $append,  'Method' => $methods), true);
            }
            if(array_key_exists($key + 1, $args)) {
                $content .= $cli ? PHP_EOL . '----------------------------------------------------------------------------------' . PHP_EOL : '<hr/>';
            }
        }
        $content .= $cli ? PHP_EOL : '</pre>';
        return $content;
    }


}


// ================================================================================================
// 为了方便,定义一个函数,之所以叫 ifif 是为了搜索时好找

function ifif($value1 = true, $value2 = true)
{
    if(func_num_args() == 0){
        return new \debuger();
    }else if(func_num_args() == 1){
        return new \debuger($value1);
    }else{
        return new \debuger($value1, $value2);
    }
}