Our code depends on require statements still and not autoloading, but rector seems to fail if a class isn't declared in a namespace matching its path.
| Subject | Details |
| :------------- | :---------------------------------------------------------------|
| Rector version | v0.8.56 |
| Installed as | composer dev dependency in project |
{
"name": "xdhmoore/ns-demo",
"require": {},
"require-dev": {
"rector/rector": "^0.8.56"
},
"autoload": {
"psr-4": {
"Api\\": "v2/"
}
},
"config": {
"optimize-autoloader": true
}
}
<?php
class Dog { }
rector process -n ./v2/animals/Dog.php
Either suggested refactorings or nothing. Don't require classes to conform to PSR-4 locations. A lack of PSR-4 conformity should cause a class not to be able to autoload another, but it probably shouldn't keep a single class from loading by itself or from classes using traditional include and require statements to reference other classes.
Error:
[ERROR] Could not process "v2/animals/Dog.php" file, due to:
"Analyze error: "Class Dog was not found while trying to analyse it - discovering symbols is probably not
configured properly.". Include your files in "$parameters->set(Option::AUTOLOAD_PATHS, [...]);" in "rector.php"
config.
See https://github.com/rectorphp/rector#configuration".
I'm new to PHP but I think what is happening is that either:
\Dog, and the autoloader can't find the file path for that\Api\animals\Dog and though the autoloader finds a file, the class inside the file isn't loaded in the expected namespace.Based on a little code spelunking, this error looks like it's coming from phpstan. It mentions discovering symbols specifically, which I see is a new alternative to autoloading in phpstan. But on the command line I can't reproduce this error using phpstan alone, so I'm guessing it has to do with how rector is using phpstan--maybe autoloading settings that rector is passing to phpstan? I have tried removing my composer autoloader.php file and composer.json autoloading settings altogether to disable autoloading, but I get the same error.
In the context of our project, the codebase is going away soon so we are hoping to move forward on a PHP 7 upgrade without spending the time converting everything to autoloading. I was trying to use rector to find some of the mandatory changes.
Apparently, I needed to explicitly add my non-autoloading root folder explicitly to the autoloading config in rector.php:
$parameters->set(Option::AUTOLOAD_PATHS, [
// or full directory
__DIR__ . '/v2'
]);
This seems to fix the problem in my demo anyway.
This doesn't totally solve the problem. I have some places were there are two classes with the same name. To continue the example, say:
<?php
class Cat { }
<?php
class Cat { }
<?php
require_once __DIR__ . '/Cat.php';
class HouseCat extends Cat { }
If I run:
rector process -n ./v2/animals/HouseCat.php
I get the following:
[ERROR] Could not process "v2/animals/HouseCat.php" file, due to:
"Analyze error: "Nette\InvalidStateException (Ambiguous class Cat resolution; defined in v2/unixtools/Cat.php
and in v2/animals/Cat.php.) thrown while looking for class HouseCat.". Include your files in
"$parameters->set(Option::AUTOLOAD_PATHS, [...]);" in "rector.php" config.
See https://github.com/rectorphp/rector#configuration".
Because both Cat.php files are loaded by the autoload setting in rector.php and it doesn't know which class is correct. I think what I want ideally is to be able to rely on require/include statements to bring classes into scope and turn off autoloading completely. I don't know if that's possible?
Hi,
the code must be valid the same way running PHP code must be. Duplicated classes, invalid PHP code etc. must be fixed first.
One way is to use the parameter approach, the other is composer.json classmap
Yeah, it looks like if I set up autoloading (PSR-4 or classmap, rector parameters or composer.json), I can't have duplicated classes, which makes sense. However, this code is running fine in prod, it just relies on require statements instead of autoloading. I think it comes back to whether there is a way to use rector/phpstan without autoloading?
I think the behavior I'm hoping for is that when "HouseCat.php" is parsed, it will see the require_once statement and pull in the v2/animals/Cat.php as specified using PHP's builtin "include" resolution. Similar to common practice before PSR-4. If only the require'd files are loaded, then duplicates don't matter.
But maybe there's not a way to do that.
It is usually possible, e.g. PHPCodeSniffer does not respect PSR-4 autoloading and had duplicated classes, but provided custom file to autoload it.
vendor/autoload.php is just formalized path for composer, but each framework had its own way to do the same. E.g. project/includes.php, that contained all the include, required or custom spl_autoload() implementation.
If you find the autolaod file of your project, you can include it and Rector will work.
Well, like I've said, I don't think the autoloader is being used by most of our code. We do have the out-of-the-box autoloader provided by composer (no autoload section in composer.json), but I think the majority of the class-loading in the code is done by require statements, not through reliance on the autoloader. When I try using the out-of-the-box autoloader setup, I get the same errors as at the top of this issue.
Unrelatedly, I'm also getting some errors where it looks like rector is trying to run the code under analysis and failing because it's running it out of context.
Thanks for your time. I appreciate it. I think I'm going to have to give up at this point and move on. I don't think I figured out the use case I was looking for, so I guess I'll leave it up to you on whether to close the issue.
but I think the majority of the class-loading in the code is done by require statements, not through reliance on the autoloader
That's correct. I don't talk about composer nor Rector, but your project's autoload entry.
The index.php (front controller) is including one or more files that are basically the autoload entry. If you're able to find it, just provide it to Rector and that's it.
Thanks for your time. I appreciate it. I think I'm going to have to give up at this point and move on. I don't think I figured out the use case I was looking for, so I guess I'll leave it up to you on whether to close the issue.
:+1:
This sound like a hard candy that would require more work and time, rather than open source issue.
I can offer you my private service and experience to resolve it.