| Subject | Details |
| :------------- | :---------------------------------------------------------------|
| Rector version | dev-master |
| Installed as | composer dependency |
So I am using Laravel IDE helper to have better suggestions in IDE. There's a _ide_loader.php file which has some classes which I then include as @mixin in PHPDoc of Models.
When I try to run rector on such code
<?php
namespace App\Services;
use App\Models\Cart;
use Auth;
use Session;
class CartService
{
/**
* @return Cart
*/
function initNewCart()
{
$cart = new Cart();
$cart->price = 0.0; // this line causes it
return $cart;
}
}
It bloats the memory over 4G and causes a segmentation fault because lack of memory available.
The underlying property price doesn't exist, it's only as a @property float $price and is available via Laravel's Model magic. The problem is that BaseModel, which I am extending in Cart class, is defined on two places: that generated ide helper & actual BaseModel class. If I load the ide helper file, it goes into fire.


When I don't autoload that file (which I should not ever load, it's only for ide's knowledge), it screams about the @mixin Eloquent I have in some of my models:
/**
* @property int $id
* ...
* @mixin Eloquent
*/
class Store extends BaseModel {
}
[ERROR] Could not process "app/Services/StoreResolver.php" file, due to:
"Analyze error: "Class Eloquent not found.". Include your files in "parameters > autoload_paths".
See https://github.com/rectorphp/rector#extra-autoloading".
Is there a way I could explicitly disable checking @mixins?
It might be something in Cart. If you replace Cart with some dummy empty class, does the problem remain?
Is there a way I could explicitly disable checking @mixins?
Not sure what does it mean, I never used Laravel. Could you share reproducible minimal code so we can see error ourselves?
Not sure what IDE helper is, but if it makes mess, you can exclude it.
It might be something in
Cart. If you replaceCartwith some dummy empty class, does the problem remain?
As soon as I remove the line I highlighted with comment, it works properly. IDE helper is simply recreating all the classes that have magic methods from Laravel and adds extra typehints, return types and more useful things. That's not necessary to underestand tho.
The problem is that rector, or some part of rector, is analyzing content DOCblock, finding @mixin Eloquent and tries to autoload that class, which is present only for IDE to recognize more methods because they are being called magically making it unable for IDE to hint it without the helper. It's not meant to be loaded, autoloaded, by PHP itself. Rector is trying to load it, which means autoload, the file, and is unable to continue without it. That file alone has 22 000 lines of code which can be a part of the reason why it uses so much memory.
Hm, black magic strikes again.
What do you suggest to keep PHPStan/Rector working on other projects but not get stuck on your code?
I am digging deeper to narrow it down to the smallest possible example I can make.
So here are things that worked out:
_ide_helper.php is now narrowed down to
<?php
class Eloquent extends \Illuminate\Database\Eloquent\Model {
}
Model.php looks like this at the top:
/**
*
* @mixin Eloquent
* @mixin \Illuminate\Database\Eloquent\Builder
* @mixin \Illuminate\Database\Query\Builder
*/
abstract class Model implements Arrayable, ArrayAccess, Jsonable, JsonSerializable, QueueableEntity, UrlRoutable
{
I thought it's some sort of infinite loop because class that Model is using @mixin and that Mixin is extending Model. But that's not the case if I try it in isolated environment.
Then I went to try to narrow down the part of code of rector causing this.
PHPStanNodeScopeResolver.php - I added these echoes
$nodeCallback = function (Node $node, MutatingScope $scope) use ($smartFileInfo): void {
echo "A";
// the class reflection is resolved AFTER entering to class node
// so we need to get it from the first after this one
if ($node instanceof Class_ || $node instanceof Interface_) {
$scope = $this->resolveClassOrInterfaceScope($node, $scope);
}
echo "b";
// traversing trait inside class that is using it scope (from referenced) - the trait traversed by Rector is different (directly from parsed file)
if ($scope->isInTrait()) {
$traitName = $scope->getTraitReflection()->getName();
$this->traitNodeScopeCollector->addForTraitAndNode($traitName, $node, $scope);
return;
}
echo $smartFileInfo->getFilename();
echo "c";
// special case for unreachable nodes
if ($node instanceof UnreachableStatementNode) {
$originalNode = $node->getOriginalStatement();
$originalNode->setAttribute(AttributeKey::IS_UNREACHABLE, true);
$originalNode->setAttribute(AttributeKey::SCOPE, $scope);
} else {
$node->setAttribute(AttributeKey::SCOPE, $scope);
}
echo "c2";
$this->resolveDependentFiles($node, $scope);
echo "c3";
};
and also var_dumped the nodes:
var_dump($nodes);
/** @var MutatingScope $scope */
$this->nodeScopeResolver->processNodes($nodes, $scope, $nodeCallback);
This is what I get if I have Eloquent mixin in Model:
Rector dev-master@7dae020
Config file: rector.php
[parsing] app/Services/CartService.php
array(1) {
[0]=>
object(PhpParser\Node\Stmt\Namespace_)#1776 (3) {
["name"]=>
object(PhpParser\Node\Name)#1792 (2) {
["parts"]=>
array(2) {
[0]=>
string(3) "App"
[1]=>
string(8) "Services"
}
["attributes":protected]=>
array(4) {
["startLine"]=>
int(3)
["startTokenPos"]=>
int(4)
["endLine"]=>
int(3)
["endTokenPos"]=>
int(4)
}
}
["stmts"]=>
array(4) {
[0]=>
object(PhpParser\Node\Stmt\Use_)#1775 (3) {
["type"]=>
int(1)
["uses"]=>
array(1) {
[0]=>
object(PhpParser\Node\Stmt\UseUse)#1615 (4) {
["type"]=>
int(0)
["name"]=>
object(PhpParser\Node\Name)#1687 (2) {
["parts"]=>
array(3) {
[0]=>
string(3) "App"
[1]=>
string(6) "Models"
[2]=>
string(4) "Cart"
}
["attributes":protected]=>
array(4) {
["startLine"]=>
int(5)
["startTokenPos"]=>
int(9)
["endLine"]=>
int(5)
["endTokenPos"]=>
int(9)
}
}
["alias"]=>
NULL
["attributes":protected]=>
array(4) {
["startLine"]=>
int(5)
["startTokenPos"]=>
int(9)
["endLine"]=>
int(5)
["endTokenPos"]=>
int(9)
}
}
}
["attributes":protected]=>
array(4) {
["startLine"]=>
int(5)
["startTokenPos"]=>
int(7)
["endLine"]=>
int(5)
["endTokenPos"]=>
int(10)
}
}
[1]=>
object(PhpParser\Node\Stmt\Use_)#1796 (3) {
["type"]=>
int(1)
["uses"]=>
array(1) {
[0]=>
object(PhpParser\Node\Stmt\UseUse)#1789 (4) {
["type"]=>
int(0)
["name"]=>
object(PhpParser\Node\Name)#1791 (2) {
["parts"]=>
array(1) {
[0]=>
string(4) "Auth"
}
["attributes":protected]=>
array(4) {
["startLine"]=>
int(6)
["startTokenPos"]=>
int(14)
["endLine"]=>
int(6)
["endTokenPos"]=>
int(14)
}
}
["alias"]=>
NULL
["attributes":protected]=>
array(4) {
["startLine"]=>
int(6)
["startTokenPos"]=>
int(14)
["endLine"]=>
int(6)
["endTokenPos"]=>
int(14)
}
}
}
["attributes":protected]=>
array(4) {
["startLine"]=>
int(6)
["startTokenPos"]=>
int(12)
["endLine"]=>
int(6)
["endTokenPos"]=>
int(15)
}
}
[2]=>
object(PhpParser\Node\Stmt\Use_)#1807 (3) {
["type"]=>
int(1)
["uses"]=>
array(1) {
[0]=>
object(PhpParser\Node\Stmt\UseUse)#1798 (4) {
["type"]=>
int(0)
["name"]=>
object(PhpParser\Node\Name)#1808 (2) {
["parts"]=>
array(1) {
[0]=>
string(7) "Session"
}
["attributes":protected]=>
array(4) {
["startLine"]=>
int(7)
["startTokenPos"]=>
int(19)
["endLine"]=>
int(7)
["endTokenPos"]=>
int(19)
}
}
["alias"]=>
NULL
["attributes":protected]=>
array(4) {
["startLine"]=>
int(7)
["startTokenPos"]=>
int(19)
["endLine"]=>
int(7)
["endTokenPos"]=>
int(19)
}
}
}
["attributes":protected]=>
array(4) {
["startLine"]=>
int(7)
["startTokenPos"]=>
int(17)
["endLine"]=>
int(7)
["endTokenPos"]=>
int(20)
}
}
[3]=>
object(PhpParser\Node\Stmt\Class_)#1810 (7) {
["flags"]=>
int(0)
["extends"]=>
NULL
["implements"]=>
array(0) {
}
["name"]=>
object(PhpParser\Node\Identifier)#1823 (2) {
["name"]=>
string(11) "CartService"
["attributes":protected]=>
array(4) {
["startLine"]=>
int(9)
["startTokenPos"]=>
int(24)
["endLine"]=>
int(9)
["endTokenPos"]=>
int(24)
}
}
["stmts"]=>
array(1) {
[0]=>
object(PhpParser\Node\Stmt\ClassMethod)#1818 (7) {
["flags"]=>
int(0)
["byRef"]=>
bool(false)
["name"]=>
object(PhpParser\Node\Identifier)#1887 (2) {
["name"]=>
string(11) "initNewCart"
["attributes":protected]=>
array(4) {
["startLine"]=>
int(11)
["startTokenPos"]=>
int(30)
["endLine"]=>
int(11)
["endTokenPos"]=>
int(30)
}
}
["params"]=>
array(0) {
}
["returnType"]=>
NULL
["stmts"]=>
array(3) {
[0]=>
object(PhpParser\Node\Stmt\Expression)#1800 (2) {
["expr"]=>
object(PhpParser\Node\Expr\Assign)#2023 (3) {
["var"]=>
object(PhpParser\Node\Expr\Variable)#1820 (2) {
["name"]=>
string(4) "cart"
["attributes":protected]=>
array(4) {
["startLine"]=>
int(13)
["startTokenPos"]=>
int(36)
["endLine"]=>
int(13)
["endTokenPos"]=>
int(36)
}
}
["expr"]=>
object(PhpParser\Node\Expr\New_)#1880 (3) {
["class"]=>
object(PhpParser\Node\Name\FullyQualified)#1815 (2) {
["parts"]=>
array(3) {
[0]=>
string(3) "App"
[1]=>
string(6) "Models"
[2]=>
string(4) "Cart"
}
["attributes":protected]=>
array(5) {
["startLine"]=>
int(13)
["startTokenPos"]=>
int(42)
["endLine"]=>
int(13)
["endTokenPos"]=>
int(42)
["originalName"]=>
object(PhpParser\Node\Name)#1933 (2) {
["parts"]=>
array(1) {
[0]=>
string(4) "Cart"
}
["attributes":protected]=>
array(4) {
["startLine"]=>
int(13)
["startTokenPos"]=>
int(42)
["endLine"]=>
int(13)
["endTokenPos"]=>
int(42)
}
}
}
}
["args"]=>
array(0) {
}
["attributes":protected]=>
array(4) {
["startLine"]=>
int(13)
["startTokenPos"]=>
int(40)
["endLine"]=>
int(13)
["endTokenPos"]=>
int(44)
}
}
["attributes":protected]=>
array(4) {
["startLine"]=>
int(13)
["startTokenPos"]=>
int(36)
["endLine"]=>
int(13)
["endTokenPos"]=>
int(44)
}
}
["attributes":protected]=>
array(4) {
["startLine"]=>
int(13)
["startTokenPos"]=>
int(36)
["endLine"]=>
int(13)
["endTokenPos"]=>
int(45)
}
}
[1]=>
object(PhpParser\Node\Stmt\Expression)#1804 (2) {
["expr"]=>
object(PhpParser\Node\Expr\Assign)#1814 (3) {
["var"]=>
object(PhpParser\Node\Expr\PropertyFetch)#1995 (3) {
["var"]=>
object(PhpParser\Node\Expr\Variable)#1799 (2) {
["name"]=>
string(4) "cart"
["attributes":protected]=>
array(4) {
["startLine"]=>
int(14)
["startTokenPos"]=>
int(47)
["endLine"]=>
int(14)
["endTokenPos"]=>
int(47)
}
}
["name"]=>
object(PhpParser\Node\Identifier)#1806 (2) {
["name"]=>
string(5) "price"
["attributes":protected]=>
array(4) {
["startLine"]=>
int(14)
["startTokenPos"]=>
int(49)
["endLine"]=>
int(14)
["endTokenPos"]=>
int(49)
}
}
["attributes":protected]=>
array(4) {
["startLine"]=>
int(14)
["startTokenPos"]=>
int(47)
["endLine"]=>
int(14)
["endTokenPos"]=>
int(49)
}
}
["expr"]=>
object(PhpParser\Node\Scalar\DNumber)#1802 (2) {
["value"]=>
float(0)
["attributes":protected]=>
array(4) {
["startLine"]=>
int(14)
["startTokenPos"]=>
int(53)
["endLine"]=>
int(14)
["endTokenPos"]=>
int(53)
}
}
["attributes":protected]=>
array(4) {
["startLine"]=>
int(14)
["startTokenPos"]=>
int(47)
["endLine"]=>
int(14)
["endTokenPos"]=>
int(53)
}
}
["attributes":protected]=>
array(4) {
["startLine"]=>
int(14)
["startTokenPos"]=>
int(47)
["endLine"]=>
int(14)
["endTokenPos"]=>
int(54)
}
}
[2]=>
object(PhpParser\Node\Stmt\Return_)#1805 (2) {
["expr"]=>
object(PhpParser\Node\Expr\Variable)#1803 (2) {
["name"]=>
string(4) "cart"
["attributes":protected]=>
array(4) {
["startLine"]=>
int(15)
["startTokenPos"]=>
int(58)
["endLine"]=>
int(15)
["endTokenPos"]=>
int(58)
}
}
["attributes":protected]=>
array(4) {
["startLine"]=>
int(15)
["startTokenPos"]=>
int(56)
["endLine"]=>
int(15)
["endTokenPos"]=>
int(59)
}
}
}
["attributes":protected]=>
array(4) {
["startLine"]=>
int(11)
["startTokenPos"]=>
int(28)
["endLine"]=>
int(16)
["endTokenPos"]=>
int(61)
}
}
}
["attributes":protected]=>
array(4) {
["startLine"]=>
int(9)
["startTokenPos"]=>
int(22)
["endLine"]=>
int(17)
["endTokenPos"]=>
int(63)
}
["namespacedName"]=>
object(PhpParser\Node\Name)#1817 (2) {
["parts"]=>
array(3) {
[0]=>
string(3) "App"
[1]=>
string(8) "Services"
[2]=>
string(11) "CartService"
}
["attributes":protected]=>
array(0) {
}
}
}
}
["attributes":protected]=>
array(5) {
["startLine"]=>
int(3)
["startTokenPos"]=>
int(2)
["endLine"]=>
int(17)
["endTokenPos"]=>
int(63)
["kind"]=>
int(1)
}
}
}
AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartServ
ice.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3 (here it hangs)
If i remove that mixin in Model class, I get
File "/mnt/c/Users/admin/Dropbox/_php/RestaurantBack/vendor/autoload.php" is about to be loaded in "AutoloadIncluder::includeCwdVendorAutoloadIfExists()" on line 102"
File "/mnt/c/Users/admin/Dropbox/_php/RestaurantBack/vendor/rector/rector/../../autoload.php" is about to be loaded in "AutoloadIncluder::autoloadProjectAutoloaderFile()" on line 136"
Rector dev-master@7dae020
Config file: rector.php
[parsing] app/Services/CartService.php
array(1) {
<<<the same var dump as above>>>
}
CartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartServ
ice.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2c3AbCartService.phpcc2
c3AbCartService.phpcc2c3AbCartService.phpcc2c3 (here it continues and finishes)
Unfortunately I wasn't narrow it down futher because it looks like It's hanging in NodeScopeResolver.php which is in phar, which I found even you had problem with finding solution to :-)
Maybe @ondrejmirtes could help a bit here, please?
It would be plenty enough to just have an ability to skip the @mixin from analyzing I think
PHPStan has an undocumented feature that you can tell it to ignore some @mixin tags. We use it at Larastan like this. Maybe this can help, if just the @mixin \Eloquent is the problem.
Just found about that haha. Thanks!
How do I set it up for rector usage tho? Is installing Larastan/setting in phpstan.neon enough?
I don't know how rector works. If you have a possiblity to have your own PHPStan config, just add
parameters:
mixinExcludeClasses:
- Eloquent
Closing as resolved with https://github.com/rectorphp/rector/issues/3836#issuecomment-668145010
Most helpful comment
I don't know how rector works. If you have a possiblity to have your own PHPStan config, just add