如何使用打印/回显检查变量是否可打印?

问题描述 投票:0回答:2

我有一个接收$ mixed值的函数。我需要检查它是否可以打印,然后以其他方式打印该值以打印其类型。

样本值

  • $ Object
  • $ string
  • $ number

和我的功能

function dmp( $value ) {
   echo $value ; 
}

在上述条件下,当我尝试打印$ Object时,会导致可捕获的错误。有没有一种方法或内置函数来检查是否可以打印值?还是我必须手动编写一个?

php echo
2个回答
2
投票

您可以使用gettype来获取变量的类型,如:

<?php

$data = array(1, 1., NULL, new stdClass, 'foo');

foreach ($data as $value) {
    echo gettype($value), "\n";
}

?>

上面的示例将输出类似于:

integer
double
NULL
object
string

更多详细信息:http://php.net/manual/en/function.gettype.php


0
投票

使用我编写的此功能:

isPrintable($input, &$text = null) : bool

下面带有一些使用和检查错误处理程序的示例的代码。

<?php

/**
 * Check if $input can be echoed
 * without any problem.
 */
function isPrintable($input, &$text = null) : bool
{
    set_error_handler(function(){throw new \Exception();});
    ob_start();

    try {
        echo $input;
        $result = true;

    } catch (\Exception $e) {
        $result = false;
    }

    if ($result) {
        $text = ob_get_contents();
    } else {
        $text = null;
    }

    ob_end_clean();
    restore_error_handler();
    return $result;
}

//-------- data for test -------
class PrintMe 
{
    public function __toString()
    {
        return "I have a magic power";
    }
}

$res = fopen("php://memory", 'w');
fclose($res);

$data = [
    'array' => ['array'],
    'stdClass' => (new \stdClass), 
    'PrintMe' => (new PrintMe), 
    'integer' => 1, 
    'float' => 1.5, 
    'null' => NULL,
    'bool = true' => true,
    'bool = false' => false,
    'string' => 'foo',
    'resource' => tmpfile(),
    'resource (unknown type)' => $res
];
//-------- data for test end ---

//set own err handler just for testing
set_error_handler(function(){echo "I am an error handler that should be present\n";});
//trigger an error and test if the defined error handler is present
trigger_error('', \E_USER_ERROR);

//------- check if printable -------
$resultArr = [];
foreach ($data as $name => $unknownTypeVariable) {
    $check = isPrintable($unknownTypeVariable) ? 'yes' : 'no';
    $resultArr[$name] = $check;
}

echo "\nisPrintable:\n";
print_r($resultArr);
echo "\n";
//------- check if printable end ---

//------- check if printable 2nd form -------
$resultArr = [];
foreach ($data as $name => $unknownTypeVariable) {

    if (isPrintable($unknownTypeVariable, $text)) {
        $resultArr[$name] = 'Printable: "' . $text . '"';

    } else {
        $resultArr[$name] = 'Not Printable';
    }
}

echo "\nisPrintable 2nd form:\n";
print_r($resultArr);
echo "\n";

//------- check if printable 2nd form end ---

//------- check if printable 2nd form v2 -------
$resultArr = [];
foreach ($data as $name => $unknownTypeVariable) {

    $msg = 'Not Printable';
    !isPrintable($unknownTypeVariable, $text) ?: $msg = 'Printable: "' . $text . '"';
    $resultArr[$name] = $msg;

}

echo "\nisPrintable 2nd form v2:\n";
print_r($resultArr);
echo "\n";
//------- check if printable 2nd form v2 end ---

//------- check if printable 3nd form -------
$resultArr = [];
foreach ($data as $name => $unknownTypeVariable) {

    isPrintable($unknownTypeVariable, $text);
    $msg = isset($text) ? 'Printable: "' . $text . '"' : 'Not Printable';
    $resultArr[$name] = $msg;

}

echo "\nisPrintable 3nd form v2:\n";
print_r($resultArr);
echo "\n";
//------- check if printable 3nd form end ---

//trigger an error and test if the error handler that was before is still present
trigger_error('', \E_USER_ERROR);

//restore error handler that was before testing
restore_error_handler();

//trigger a fatal error - check if restored error handler works
trigger_error('Restored error handler works', \E_USER_ERROR);

给出输出:

I am an error handler that should be present

isPrintable:
Array
(
    [array] => no
    [stdClass] => no
    [PrintMe] => yes
    [integer] => yes
    [float] => yes
    [null] => yes
    [bool = true] => yes
    [bool = false] => yes
    [string] => yes
    [resource] => yes
    [resource (unknown type)] => yes
)


isPrintable 2nd form:
Array
(
    [array] => Not Printable
    [stdClass] => Not Printable
    [PrintMe] => Printable: "I have a magic power"
    [integer] => Printable: "1"
    [float] => Printable: "1.5"
    [null] => Printable: ""
    [bool = true] => Printable: "1"
    [bool = false] => Printable: ""
    [string] => Printable: "foo"
    [resource] => Printable: "Resource id #6"
    [resource (unknown type)] => Printable: "Resource id #5"
)


isPrintable 2nd form v2:
Array
(
    [array] => Not Printable
    [stdClass] => Not Printable
    [PrintMe] => Printable: "I have a magic power"
    [integer] => Printable: "1"
    [float] => Printable: "1.5"
    [null] => Printable: ""
    [bool = true] => Printable: "1"
    [bool = false] => Printable: ""
    [string] => Printable: "foo"
    [resource] => Printable: "Resource id #6"
    [resource (unknown type)] => Printable: "Resource id #5"
)


isPrintable 3nd form:
Array
(
    [array] => Not Printable
    [stdClass] => Not Printable
    [PrintMe] => Printable: "I have a magic power"
    [integer] => Printable: "1"
    [float] => Printable: "1.5"
    [null] => Printable: ""
    [bool = true] => Printable: "1"
    [bool = false] => Printable: ""
    [string] => Printable: "foo"
    [resource] => Printable: "Resource id #6"
    [resource (unknown type)] => Printable: "Resource id #5"
)

I am an error handler that should be present

Fatal error: Restored error handler works in <path-to-your-php-script> on line 130

您所需要的只是函数isPrintable,但是最好保存为以后使用检查错误处理程序的示例,就像我以前所做的那样,将来您可以再次检查isPrintable是否在更新的PHP版本中按预期工作。可能最好的方法是编写一个涵盖该内容的PHPUnit测试。

这非常重要,因为在使用错误处理程序时未100%成功会给您带来很长一段时间可以跟踪的错误。

输出是使用PHP 7.3.8生成的isPrintable也应该与PHP 5兼容,但我尚未对其进行测试。

如果您不想将函数用于error_handlers并引发异常,则可以使用method_exists检查对象是否实现了__toString方法。

echo method_exists(new PrintMe, '__toString') ? "yes" : "no";

打印“是”;

echo method_exists(new \stdClass, '__toString') ? "yes" : "no";

打印“否”

并使用is_array检查变量是否为数组。

或者如果您还希望打印实现__toString的对象,则最好使用gettype获取变量的类型并使用要打印的类型的白名单对其进行检查,并使用__toString的method_exists。

isPrintable2给出的结果与isPrintable相同,但是不使用错误处理程序或异常,因此它应该更快。但是,由于它在编写时就知道了变量类型列表,因此它可以工作,因此将来可能会抛出InvalidArgumentException。但是,如果这样做,则只需要用该新类型更新$knownListArr,如果您想打印它,就只需更新$printableListArr

/**
 * Check if $input can be echoed
 * without any problem.
 */
function isPrintable2($input, &$text = null) : bool
{
    $result = true;
    $type = gettype($input);

    $knownListArr = [
        'array',
        'NULL',
        'object',
        'integer',
        'double',
        'boolean',
        'string',
        'resource',
        'resource (closed)'
    ];

    $printableListArr = [
        'NULL',
        'object',
        'integer',
        'double',
        'boolean',
        'string',
        'resource',
        'resource (closed)'
    ];

    if (!in_array($type, $knownListArr)) {
        $msg = 'Unknown variable type: ' . $type;
        $text = null;
        throw new \InvalidArgumentException($msg);
    }

    if (!in_array($type, $printableListArr)) {
        $result = false;
    }

    if ($result && 
        $type === 'object' && 
        !method_exists($input, '__toString')) 
    {
        $result = false;
    }

    if ($result) {
        $text = (string) $input;
    } else {
        $text = null;
    }

    return $result;
}

[需要注意的是,echo [];实际上将使用PHP的警告将Array字符串打印为数组转换为字符串。另外,如果您echo null;,您将得到一个空字符串"",如果您执行echo false;

因为falsenull完全不同,所以以人类可读性的方式处理这种情况可能会比较好,例如以字符串形式显示它们:falseNULL而不是误导性的空字符串。

[echo true;也打印字符串1,与echo 1;相同,但是如上所述echo false;打印一个空字符串,而不是0

如您所见,检测变量是否可打印是一回事,但是例如以明显的方式打印以进行调试是另一回事。

© www.soinside.com 2019 - 2024. All rights reserved.