The real issue is you're using Laravel 4.2. In the current laravel version (11.x at the time of writing this), the code would not trip PHPStan because the Eloquent Builder implements the following interface.
<?php
namespace Illuminate\Contracts\Database\Query;
/**
* This interface is intentionally empty and exists to improve IDE support.
*
* @mixin \Illuminate\Database\Query\Builder
*/
interface Builder
{
}
In laravel 4.2, the Eloquent Builder does not implement an interface, or extend the base Builder.
Every method not found in the Eloquent Builder is sought in the defined macros, and then delegated to the base Builder (which is a property)
For comparison:
laravel 4.2's Eloquent Builder
<?php
namespace Illuminate\Database\Eloquent;
...
class Builder
{
/**
* The base query builder instance.
*
* @var \Illuminate\Database\Query\Builder
*/
protected $query;
...
/**
* Dynamically handle calls into the query instance.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
if (isset($this->macros[$method]))
{
array_unshift($parameters, $this);
return call_user_func_array($this->macros[$method], $parameters);
}
elseif (method_exists($this->model, $scope = 'scope'.ucfirst($method)))
{
return $this->callScope($scope, $parameters);
}
$result = call_user_func_array(array($this->query, $method), $parameters);
return in_array($method, $this->passthru) ? $result : $this;
}
...
}
laravel 11.x's Eloquent Builder
<?php
namespace Illuminate\Database\Eloquent;
...
use Illuminate\Contracts\Database\Eloquent\Builder as BuilderContract;
...
/**
* @template TModel of \Illuminate\Database\Eloquent\Model
*
* @property-read HigherOrderBuilderProxy $orWhere
* @property-read HigherOrderBuilderProxy $whereNot
* @property-read HigherOrderBuilderProxy $orWhereNot
*
* @mixin \Illuminate\Database\Query\Builder
*/
class Builder implements BuilderContract
{
...
/**
* The base query builder instance.
*
* @var \Illuminate\Database\Query\Builder
*/
protected $query;
...
}
In fact it even adds the @mixin annotation again.
A quick and dirty fix you could do would be to edit the vendor class to add the /** * @mixin \Illuminate\Database\Query\Builder */ annotation on top of the Illuminate\Database\Eloquent\Query\Builder class. Of course, if you update your dependencies and the laravel version changes (or you (re)install them, this line will need to get re-added.
Editing vendor code should be avoided, but
- This is a phpdoc block and carries no actual functionality.
- If your project has laravel 4.2, I don't think you're updating dependencies all that often enough for this to break.