tsingsun / yii2-swoole

make yii2 project runing on swoole
BSD 3-Clause "New" or "Revised" License
162 stars 23 forks source link

php7.2中count函数出现Parameter must be an array or an object that implements Countable #9

Open sdscbr opened 5 years ago

sdscbr commented 5 years ago

1.运行环境 centos7 Linux 3.10.0-957.el7.x86_64 php7.2.19 swoole4.3.5 yii2-basic 2.0.20 2.在开启日志功能,将日志信息写入到数据库表中时,会报下面的错误:

2019-06-26 19:44:49 [192.168.134.1][-][-][warning][yii\log\Dispatcher::dispatch] Unable to send log via yii\log\DbTarget: Exception (Database Exception) 'yii\db\Exception' with message 'count(): Parameter must be an array or an object that implements Countable
The SQL being executed was: INSERT INTO `log` (`level`, `category`, `log_time`, `prefix`, `message`)
                VALUES (8, 'tsingsun\swoole\web\Application::runComponentBootstrap', 1561635889.3354, '[192.168.134.1][-][-]', 'Bootstrap with yii\gii\Module::bootstrap()')' 

in /usr/local/nginx/html/yii2-basic-swoole/vendor/yiisoft/yii2/db/Schema.php:664

Stack trace:
#0 /usr/local/nginx/html/yii2-basic-swoole/vendor/tsingsun/yii2-swoole/src/db/Command.php(325): yii\db\Schema->convertException(Object(yii\base\ErrorException), 'INSERT INTO `lo...')#1 /usr/local/nginx/html/yii2-basic-swoole/vendor/yiisoft/yii2/log/DbTarget.php(93): tsingsun\swoole\db\Command->execute()
#2 /usr/local/nginx/html/yii2-basic-swoole/vendor/yiisoft/yii2/log/Target.php(158): yii\log\DbTarget->export()
#3 /usr/local/nginx/html/yii2-basic-swoole/vendor/yiisoft/yii2/log/Dispatcher.php(189): yii\log\Target->collect(Array, false)
#4 /usr/local/nginx/html/yii2-basic-swoole/vendor/yiisoft/yii2/log/Logger.php(177): yii\log\Dispatcher->dispatch(Array, false)
#5 /usr/local/nginx/html/yii2-basic-swoole/vendor/tsingsun/yii2-swoole/src/log/Logger.php(54): yii\log\Logger->flush(false)
#6 /usr/local/nginx/html/yii2-basic-swoole/vendor/yiisoft/yii2/BaseYii.php(395): tsingsun\swoole\log\Logger->log('Bootstrap with ...', 8, 'tsingsun\\swoole...')
#7 /usr/local/nginx/html/yii2-basic-swoole/vendor/yiisoft/yii2/BaseYii.php(408): yii\BaseYii::debug('Bootstrap with ...', 'tsingsun\\swoole...')
#8 /usr/local/nginx/html/yii2-basic-swoole/vendor/tsingsun/yii2-swoole/src/web/Application.php(126): yii\BaseYii::trace('Bootstrap with ...', 'tsingsun\\swoole...')
#9 /usr/local/nginx/html/yii2-basic-swoole/vendor/tsingsun/yii2-swoole/src/web/Application.php(68): tsingsun\swoole\web\Application->runComponentBootstrap()
#10 /usr/local/nginx/html/yii2-basic-swoole/vendor/tsingsun/yii2-swoole/src/web/Application.php(56): tsingsun\swoole\web\Application->bootstrap()
#11 /usr/local/nginx/html/yii2-basic-swoole/vendor/tsingsun/yii2-swoole/src/bootstrap/WebApp.php(39): tsingsun\swoole\web\Application->beforeRun()
#12 /usr/local/nginx/html/yii2-basic-swoole/vendor/tsingsun/yii2-swoole/src/bootstrap/BaseBootstrap.php(124): tsingsun\swoole\bootstrap\WebApp->handleRequest(Object(Swoole\Http\Request), Object(Swoole\Http\Response))#13 /usr/local/nginx/html/yii2-basic-swoole/vendor/tsingsun/yii2-swoole/src/server/HttpServer.php(40): tsingsun\swoole\bootstrap\BaseBootstrap->onRequest(Object(Swoole\Http\Request), Object(Swoole\Http\Response))#14 {main}

不过,日志信息是可以正常插到数据库里,经过跟踪代码,问题出在这个文件:

tsingsun/yii2-swoole/src/db/mysql/PDOStatement.php

下面这个函数:

    public function rowCount()
    {   
       return count($this->data);         
    }

$this->data的值可能是数字或者数组,当是数字时在PHP7.2上会有警告,参考官方文档: https://www.php.net/manual/en/function.count.php 下面是一种解决办法:

    public function rowCount()
    {   
        if (is_array($this->data) || (($this->data) instanceof \Countable)) {
            return count($this->data);
        } else {
            return $this->data;
        }   
    }

这应该是个兼容问题,还有没有其他更好的解决方法,可以一起交流一下,谢谢~~

tsingsun commented 5 years ago

@sdscbr 这是一个bug,而swoole本身对select的影响行数并不支持,会增加一个字段来记录影响行数

    /**
     * @var int
     * @see rowCount
     */
    private $affected_rows;

    /**
     * swoole并不支持select返回影响数据行
     * Returns the number of rows affected by the last SQL statement
     * @link https://php.net/manual/en/pdostatement.rowcount.php
     * @return int the number of rows.
     */
    public function rowCount()
    {
        if (is_array($this->data)){
            return count($this->data);
        }
        return $this->affected_rows;
    }

affected_rows会在query执行时,被影响

    public function execute($input_parameters = null)
    {
        try {
            $client = $this->pdo->getClient();
            $this->data = $client->query($this->getRawSql());
            $this->affected_rows = $client->affected_rows;
            if ($this->data === false && $client->error != null) {
                throw new \PDOException($client->error,$client->errno);
            }
        } finally {
            if (!$this->pdo->inTransaction()) {
                $this->pdo->releaseConnect();
            }
        }
        return is_array($this->data);
    }