我有一个接收$ mixed值的函数。我需要检查它是否可以打印,然后以其他方式打印该值以打印其类型。
样本值
和我的功能
function dmp( $value ) {
echo $value ;
}
在上述条件下,当我尝试打印$ Object时,会导致可捕获的错误。有没有一种方法或内置函数来检查是否可以打印值?还是我必须手动编写一个?
您可以使用gettype来获取变量的类型,如:
<?php
$data = array(1, 1., NULL, new stdClass, 'foo');
foreach ($data as $value) {
echo gettype($value), "\n";
}
?>
上面的示例将输出类似于:
integer
double
NULL
object
string
使用我编写的此功能:
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;
因为false
和null
完全不同,所以以人类可读性的方式处理这种情况可能会比较好,例如以字符串形式显示它们:false
和NULL
而不是误导性的空字符串。
[echo true;
也打印字符串1
,与echo 1;
相同,但是如上所述echo false;
打印一个空字符串,而不是0
。
如您所见,检测变量是否可打印是一回事,但是例如以明显的方式打印以进行调试是另一回事。