方法的可选参数,当作为字符串传递时,变成数组

Method's optional parameter, when passed as string, becomes an array

Tl;dr: 在底部

设置:

我有一个 cron 作业调用 PHP 脚本来处理一些后端任务。为简单起见,cron 作业将所有输出重定向到一个日志文件。因为这对我在下面发现的实际问题很重要,所以这里是 cron 作业的净化格式:

15 4 * * * php /usr/local/bin/myScript.php >> /home/$USER/scriptLogs/myScript.log 2>&1

我是 OOP 的新手,我的任务是边学边学,对于 myScript.php,我正在做一些需要查询数据库以验证数据的数据导入在导入之前,我应该记录每笔交易。我们最近从 5.6 迁移到 7.2,手头的部分任务是在重构时使用 7.2 的新功能。

重构本身就是将所有重复的代码移至类以遵守DRY原则。

以前,它看起来像这样:

<?php namespace CronJobs

use PDO;
use Exception;

class JobAt415 {

private function getDBconnection()
{
    // connects to a DB through environment variable set in a config file
    return $db;
}
 
public function query1($parameter1, $parameter2, $inclusionParameter)
{
    $sql = "SELECT " . $parameter1 . ", ". $parameter2 . " FROM `foo`.`bar` WHERE " . $inclusionParmeter " IS NOT NULL;";
    try
    {
        $db = $this->getDBconnection();
        echo '[' . strftime("%c") . '] Running query 1' . PHP_EOL;
        $resultDictionary = $db->query($sql)->fetchall(PDO::FETCH_KEY_PAIR)
        return $resultDictionary;
    }
    catch (Exception $e)
    {
        echo '[' . strftime("%c") . '] ERRORS ' . PHP_EOL;
        echo $e->getMessage();
        return null;
    }
}

public function query2($parameter1, $parameter3)
{
    $sql = "SELECT " . $parameter1 . " FROM `foo`.`bar` WHERE " . $parameter3 " > 0;";
    try
    {
        $db = $this->getDBconnection();
        echo '[' . strftime("%c") . '] Running query 1' . PHP_EOL;
        $resultDictionary = $db->query($sql)->fetchall()
        return $resultArray;
    }
    catch (Exception $e)
    {
        echo '[' . strftime("%c") . '] ERRORS ' . PHP_EOL;
        echo $e->getMessage();
        return null;
    }
  }
}

Post-重构:

<?php namespace CronJobs

use PDO;
use Exception;

Class DbConnectionFactory {

protected $dbConnection;

public function __construct()
{
    $this->dbConnection = $this->createConnection();
}

public function runQuery($sql, ...$queryDescriptor)
{
    try
    {
        $descriptor = $queryDescriptor ? (string) $queryDescriptor : $sql;
        echo '[' . strftime("%c") . '] Running query ' . "$descriptor"  . PHP_EOL;
        $resultPending = $this->dbConnection->query($sql);
        echo '[' . strftime("%c") . '] Query successful.' . PHP_EOL;
        return $resultPending;
    }
    catch (Exception $e)
    {
        echo '[' . strftime("%c") . '] ERRORS ' . PHP_EOL;
        echo $e->getMessage();
        return null;
    }
}

public function runQueryFetchDictionary($sql, ...$queryDescriptor)
{
    $description = (string) $queryDescriptor;
    $fetchAll = $this->runQuery($sql, $description)->fetchall(PDO::FETCH_KEY_PAIR);
    return $fetchAll;
}   

// In the JobAt415 class 
private function runQuery1()
{
    $sql = 'SELECT `parameter1`, `parameter2` FROM `foo`.`bar` WHERE `baz` IS NOT NULL;';
    $description = 'p1, p2 :: baz != NULL';
    $p1Dictionary = $this->db->runQueryFetchDictionary($sql, $descripton); // $this->db is an instantiation of the DbConnectionFactory class

所以,现在我只是将 SQL 查询作为参数传递,并描述要回显到日志中的查询内容,并且我没有 19 try/catch 块我从这个例子中删除的代码或一堆重复的代码。

不幸的是,当我使用 XDebug 单步执行代码时,可选参数 $queryDescriptor 正在从字符串转换为数组。我尝试了多种传递它、转换它、and/or 定义它并得到相同结果的方法:$queryDescriptor 是一个数组。有一次,将其转换为字符串会返回“Array”的值。

当我查看 PHP website 时,我发现了这个:


Note:

The behaviour of an automatic conversion to array is currently undefined.


强调我的。

我不想要任何转换。那么,我该如何防止呢?有人看到我错过了什么吗?为什么 $sql 字符串不转换为数组,而 $queryDescriptor 总是被转换?

Tl;博士:

为什么我的字符串现在是一个数组?

因为通过添加像 ...$queryDescriptor 这样的参数,您告诉 PHP 可以有无穷无尽的参数。这是因为变量名前面的...。这就是 PHP 将类型更改为数组的原因。

否则你如何处理可能有数千个参数的数量?

https://secure.php.net/manual/en/functions.arguments.php#functions.variable-arg-list

//You tell PHP that there can be a variable number of parameters by adding '...' in front of the variable name
function foo(...$bar) {
    //You get an array holding all the passed parameters
    foreach($bar as $arg) {
        //By stepping through it you get all the parameters
        echo $arg;
    }
}

当然也可以通过索引获取参数

$bar[0]; //returns the first passed parameter