如何检查变量是否可以使用print / echo打印?

时间:2017-11-17 07:23:26

标签: php echo

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

示例值

  • $ Object
  • $ string
  • $数目

我的功能

""

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

3 个答案:

答案 0 :(得分: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

答案 1 :(得分:0)

有些类可以由echo打印,有时候类会将__toString()方法实现为方便的转换。

以下代码尝试捕获此信息,但可能还有其他情况会发生转换......

class test1 {
    public function __toString()    {
        return "Class test1";
    }
}

class test2 {

}
function dmp ( $value ) {
    if ( is_object($value)  ) {
        if ( method_exists($value, '__toString') ) {
            echo $value;
        }
        else    {
            echo "class=".get_class($value);
        }
    }
    else    {
        try {
            echo $value;
        }
        catch ( Error $e )  {
            echo gettype($value);
        }
    }
}

$values = [ "string", 0, new test1(), new test2(), [1,2,3]];
foreach ( $values as $value )   {
    dmp($value);
}

答案 2 :(得分: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测试。

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

输出是用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检查变量是否为数组。

或者也许最好使用gettype来获取变量的类型,并使用要打印的类型白名单检查它,如果要打印实现__toString的对象,则使用__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

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