count():参数必须是实现Countable的数组或对象

时间:2018-01-19 14:43:04

标签: laravel laravel-5 laravel-scout

我面临着奇怪的情况。我在生产环境中遇到错误,而在开发环境中工作正常。

发展: Laravel 5.4.28 PHP 7.0.13 MYSQL 5.7.17

生产: Laravel 5.4.28 PHP 7.2.1 MYSQL 5.7.20

在实施代码中。我用过:

namespace App;
use Illuminate\Support\Facades\Storage;
use Laravel\Scout\Searchable;
use Illuminate\Database\Eloquent\Model;

class Artwork extends Model
{
  use Searchable;

在开发中它运作良好。但在生产中它给了我这个错误: count():参数必须是实现Countable的数组或对象 在Builder.php中(第936行)

你可以在这张照片中看到: enter image description here 不知道这背后的原因是什么?以及如何解决?

13 个答案:

答案 0 :(得分:15)

这是documented change in PHP 7.2。您需要将Laravel更新为5.6或将PHP降级到7.1版。

答案 1 :(得分:11)

/ 将此代码放在路由文件的开头,即可正常运行 /

if(version_compare(PHP_VERSION, '7.2.0', '>=')) {
    error_reporting(E_ALL ^ E_NOTICE ^ E_WARNING);
}

答案 2 :(得分:5)

在php 7.2+中,计数不适用于关系对象,您需要使用:

$ model-> relation()-> exists()

不是这样(低于php 7.2):

count($ model-> relation)

答案 3 :(得分:2)

替换

$originalWhereCount = count($query->wheres);

通过

$originalWhereCount = count((array)$query->wheres);

  

\ vendor \ laravel \ framework \ src \ Illuminate \ Database \ Eloquent \ Builder.php

答案 4 :(得分:2)

当我更新到 PHP 7.2 时,我的服务器使用的是 PHP 7.1

搜索后,我发现了为什么会这样。 (这是由于PHP更新引起的。)

因此,在我的情况下,错误是通过类型转换解决的。

我只是更新我以前计算过的所有代码

之前

y

更新后

    import numpy as np
    from sklearn.ensemble import RandomForestRegressor
    from sklearn.model_selection import train_test_split
    from sklearn.preprocessing import StandardScaler

    stages = [102, 103, 104, 106]
    reject_count = [1, 3, 1, 2]
    li = []
    li.append(stages)
    l2 = []
    l2.append(reject_count)
    x = np.array(li)
    y = np.array(reject_count)
    x.shape
    y.shape

    X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=0)
    print("===============")

    sc = StandardScaler()
    X_train = sc.fit_transform(X_train)
    X_test = sc.transform(X_test)

    regressor = RandomForestRegressor(n_estimators=100, random_state=0)
    print("x train", X_train)
    print("y train", y_train)
    regressor.fit(X_train, y_train)
    y_pred = regressor.predict(X_test)
    print(y_pred)

好运

答案 5 :(得分:1)

寻找可数参数的模型:

class ClassName extend Model {
    protected $fillable=['column_name']; // column in DB of Model is in array
}

答案 6 :(得分:1)

我遇到了同样的问题(PHP 7.2 + Laravel 5.3),但是我在这里看不到任何“好的”答案。对我来说,当我尝试从模型SomeModel::forUser() calls scopeForUser()上的作用域方法启动Builder时,就会出现问题。尝试构建新查询时,它在没有初始值(count($this->wheres))的null上跳闸。因为对作用域的魔术静态调用启动了构建器,所以没有在对象中放置其他条件,因此该属性此时仍为null

我认为有必要先分享我的解决方案,然后再思考为什么我认为它比Ben的回答更好。这不是私人的,我只是不同意。

解决方案

我从this answer那里得到了一个提示,它要重写某些核心Illuminate\Database类...

  1. 扩展Illuminate\Database\Eloquent\Model
    我的是App\Overrides\Database\Eloquent\Model
  2. 扩展Illuminate\Database\Eloquent\Builder
    我的是App\Overrides\Database\Eloquent\Builder
  3. 扩展Illuminate\Database\Query\Builder
    猜一下? App\Overrides\Database\Query\Builder
  4. 告诉Laravel使用您的Eloquent\Model
    config / app.php 'aliases'数组,替换'Eloquent'
    与您的Eloquent\Model FQN

我的Model

namespace App\Overrides\Database\Eloquent;

/*
 * Notes:
 * * Using replacement Query\Builder with ALIAS
 * * Use of Builder in this class is MY Eloquent\Builder
 */
use App\Overrides\Database\Query\Builder as QueryBuilder;
use Illuminate\Database\Eloquent\Model as EloquentModel;

class Model extends EloquentModel
{
    public function newEloquentBuilder($query)
    {
        return new Builder($query);
    }

    protected function newBaseQueryBuilder()
    {
        $conn = $this->getConnection();

        $grammar = $conn->getQueryGrammar();

        return new QueryBuilder($conn, $grammar, $conn->getPostProcessor());
    }
}

我的Eloquent\Builder

namespace App\Overrides\Database\Eloquent;

use Illuminate\Database\Eloquent\Builder as EloquentBuilder;

class Builder extends EloquentBuilder
{
    public function __construct($query)
    {
        parent::__construct($query);

        /*
         * FIX #1: Set properties treated AS arrays
         *         to empty arrays on construct.
         */
        $this->wheres = [];
        // Any other properties treated as arrays should also be initialized.
    }
}

我的Query\Builder

namespace App\Overrides\Database\Query;

use Illuminate\Database\Query\Builder as QueryBuilder;

class Builder extends QueryBuilder
{
    public function __construct()
    {
        parent::__construct(...func_get_args());

        /*
         * FIX #2: Set properties treated AS arrays
         *         to empty arrays on construct.
         */
        $this->wheres = [];
        // Any other properties treated as arrays should also be initialized.
    }
}

这安全地保留了框架的功能,因为您所做的唯一实际更改是初始化应该放在首位的属性。其他所有内容都将通过用于动态加载和依赖项注入的instanceof检查。

意见

虽然我同意@ ben-harold的评论,但他不同意“解决方案”。对于一个更为复杂的问题,这过于简单了。

升级Laravel:为确保对PHP 7.2的支持,跳多个次要版本(如果不是主要版本)对于许多团队来说是不切实际的。从长远来看,当然可以。作为我可以做的一些事情,可以在最后期限内摆脱错误?不。升级需要大量计划,并且随着结构,名称和功能的更改,经常需要进行大量重写。这是要确定优先级的事情,但不是现在需要的答案。

PHP降级:同样的问题。降级到PHP 5.x意味着A)PHP是EOL,对于拥有安全策略的许多客户而言,这可能是一个破坏交易的事物,并且B)必须放弃使用PHP 7.x语言功能的任何使用。与升级框架一样,这很可能引起很多麻烦。这也是一种不太有用的解决方案,因为使用该语言向后走会使您走得更远,并且需要更多的长期努力。

答案 7 :(得分:0)

将下面的行ob代码放在控制器中的类名之前

if (version_compare(PHP_VERSION, '7.2.0', '>=')) {
// Ignores notices and reports all other kinds... and warnings
error_reporting(E_ALL ^ E_NOTICE ^ E_WARNING);
// error_reporting(E_ALL ^ E_WARNING); // Maybe this is enough
}

答案 8 :(得分:0)

在您的web.php文件中添加以下代码

if (version_compare(PHP_VERSION, '7.2.0', '>=')) {

    error_reporting(E_ALL ^ E_NOTICE ^ E_WARNING);
}

答案 9 :(得分:0)

我在使用外部创建的表时遇到了同样的问题(不使用迁移或命令), 创建模型后,我只是分配了一个表名,但是问题出在我的模型protected $fillable中,我在其中分配了字符串而不是数组,并且发生了错误。 有两种可能的解决方案。

  1. 将数组分配给您的protected $fillable = ['filed1', 'filed2'];
  2. 完全删除protected $fillable(不推荐)
class Abc extends Model
{
     protected  $table = 'cities';
     protected $fillable = ['field1','field2', ...];
}

答案 10 :(得分:0)

'vendor \ laravel \ framework \ src \ Illuminate \ Database \ Eloquent \ Builder.php'到:

$originalWhereCount = is_array($query->wheres) ? count($query->wheres) : 0;

答案 11 :(得分:0)

I; m使用laravel 6.x 在这种情况下,您可以使用以下方式:

 $id = \DB::table('xxxx')->where('id', $id)->count();

答案 12 :(得分:-2)

我在Laravel 5.6中解决了这个问题

//在控制器中

public function index()
{
$todos = Todo::all();
return view('todos.index')->with(['todos' => $todos]);

}

//在视图页面

@if(count($todos) > 0)
  @foreach($todos as $todo)
    <div class="well">
      <h3>{{$todo->text}}</h3>
      <span class="label label-danger">{{$todo->due}}</span>
    </div>
  @endforeach
@endif