0

My PHP version is 7.1.31 and Laravel version is 4.2. I want to use phpstan as my static analysis tool.

When I run it, it outputs so many errors.

Examples are:

  1. Call to an undefined method Illuminate\Database\Eloquent\Builder::join()
  2. Call to an undefined method Illuminate\Database\Eloquent\Builder::select()
  3. Call to an undefined static method \Post::where()
  4. Call to an undefined static method Illuminate\Support\Facades\Route::get().
  5. Call to an undefined static method Illuminate\Support\Facades\Route::post().

Sample code

$results = Post::join('users', 'posts.user_id', '=', 'users.id')
          ->select('users.name', 'users.email', 'posts.title')
          ->get(); 

This is my sample config file:

parameters:

    paths:
        - application

    level: 8
6
  • 1
    I can't even search your version (4.x) of laravel in their docs, you should upgrade your app first asap Commented Nov 12, 2024 at 17:07
  • PHPStan v1 requries PHP v7.2+ and PHPStan v2 requires PHP v7.4+. Commented Nov 12, 2024 at 17:52
  • Unfortunately I can't upgrade my app right now. I installed PHPStan v1. 4. Since I think it is the specific version that supports Php 7.1. Commented Nov 13, 2024 at 0:38
  • phpstan doesnt support dynamic facade classes that are resolved during runtime. You could say that it doesnt support laravel. You can resolve it by using the IDE_helper file from barry github.com/barryvdh/laravel-ide-helper/tree/v1.8.1 like suggested in here github.com/phpstan/phpstan/issues/239 Commented Nov 13, 2024 at 12:31
  • 1
    Why would you think it's a good idea to run static analysis against framework code that's more than a decade old? What did you expect would happen besides "so many errors"? lol Commented Jan 28 at 19:29

1 Answer 1

2

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

  1. This is a phpdoc block and carries no actual functionality.
  2. If your project has laravel 4.2, I don't think you're updating dependencies all that often enough for this to break.
Sign up to request clarification or add additional context in comments.

1 Comment

Alternatively, consider lowering phpstan's level since making it pass with such an old laravel version is bound to need many hacks such as this. Start it at 1, make that pass, then try and make level 2 pass and so on. I think <= 5 should be your cap

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.