Skip to content

Commit c615c3e

Browse files
committed
Add new extension-mage-autoload.neon to run stan without static reflection
This extension provides 2 configs: extension-mage-autoload.neon (without static reflection, Mage is autoloaded and executed) extension.neon (Mage.php is not executed thanks to the static reflection) Both modes now run with similar performance, thanks to the config cacheing.
1 parent c6b31c1 commit c615c3e

File tree

6 files changed

+110
-22
lines changed

6 files changed

+110
-22
lines changed

README.md

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ It doesn't require db connection to run.
66

77
## Usage
88

9-
Add `phpstan.neon` to your Magento 1 project.
9+
Add `phpstan.neon` to your Magento 1/OpenMage project.
1010

1111
Make sure it has
1212

@@ -40,10 +40,6 @@ includes:
4040
- vendor/macopedia/phpstan-magento1/extension.neon
4141
parameters:
4242
magentoRootPath: %currentWorkingDirectory%/htdocs
43-
paths:
44-
- %currentWorkingDirectory%/path/to/magento/app/code/local
45-
autoload_files:
46-
- %currentWorkingDirectory%/path/to/magento/app/Mage.php
4743
paths:
4844
#lets start small with just our extensions
4945
- %currentWorkingDirectory%/app/code/local/VendorName/ModuleName
@@ -56,7 +52,7 @@ parameters:
5652

5753
## Data/SQL scripts can't be tested
5854

59-
Since these scripts use a presumed $this variable due to being included from a setup class, work is needed to:
55+
Since these scripts use a presumed `$this` variable due to being included from a setup class, work is needed to:
6056

6157
* work out the correct setup class
6258
* somehow make phpstan aware of it for the file
@@ -65,7 +61,7 @@ Since these scripts use a presumed $this variable due to being included from a s
6561

6662
This causes subsequent calls to the class object to assume the scope of the super-class that defined the return type.
6763

68-
This is due to their PHPDoc not using the up to date way of specifying fluency with subclasses using "$this" as the type.
64+
This is due to their PHPDoc not using the up to date way of specifying fluency with subclasses using `$this` as the type.
6965

7066
Options to resolve:
7167

@@ -74,7 +70,7 @@ Options to resolve:
7470
* Define @method PHPDoc for the called methods in the subclass
7571
* Add the error to the parameters.ignoreErrors phpstan configuration to ignore it - this loses the ability to properly type the subseqent methods of the fluent interface
7672

77-
## Mage_Core_Model_Abstract::load $id is not an integer
73+
## Mage_Core_Model_Abstract::load `$id` is not an integer
7874

7975
This is due to an inadequate PHPDoc of the load method of the Mage_Core_Model_Abstract class. It should have used a "mixed" type to support when a field is specified as the 2nd argument.
8076

extension-mage-autoload.neon

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# This configuration file doesn't use static reflection for loading Mage class (so it executes code of Mage file).
2+
# Make sure you DON'T have local.xml file in your project when using this config. Otherwise you'll get errors
3+
# about connecting to db
4+
# this config will also throw warnings "PHP Warning: Constant DS already defined in", this is an issue in phpstan
5+
# https://github.com/phpstan/phpstan/issues/6744#event-6194525980
6+
parametersSchema:
7+
magentoRootPath: string()
8+
parameters:
9+
magentoRootPath: %currentWorkingDirectory%/htdocs
10+
staticReflection: false
11+
excludePaths:
12+
- */app/code/local/*/*/data/*
13+
- */app/code/local/*/*/sql/*
14+
bootstrapFiles:
15+
- %magentoRootPath%/app/Mage.php
16+
- phpstan-bootstrap-mage-autoload.php
17+
18+
typeAliases:
19+
Mage_Catalog_Model_Entity_Product_Collection: 'Mage_Catalog_Model_Resource_Product_Collection'
20+
callback: 'callable'
21+
earlyTerminatingMethodCalls:
22+
Mage:
23+
- throwException
24+
25+
services:
26+
-
27+
class: PHPStanMagento1\Reflection\Varien\Object\MagicMethodsReflectionExtension
28+
tags:
29+
- phpstan.broker.methodsClassReflectionExtension
30+
-
31+
class: PHPStanMagento1\Type\Mage\CoreModelLayout\Helper
32+
tags:
33+
- phpstan.broker.dynamicMethodReturnTypeExtension
34+
-
35+
class: PHPStanMagento1\Type\Mage\CoreModelLayout\GetBlockSingleton
36+
tags:
37+
- phpstan.broker.dynamicMethodReturnTypeExtension
38+
-
39+
class: PHPStanMagento1\Type\Mage\GetModel
40+
tags:
41+
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
42+
-
43+
class: PHPStanMagento1\Type\Mage\GetResourceModel
44+
tags:
45+
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
46+
-
47+
class: PHPStanMagento1\Type\Mage\GetSingleton
48+
tags:
49+
- phpstan.broker.dynamicStaticMethodReturnTypeExtension
50+
-
51+
class: PHPStanMagento1\Type\Mage\Helper
52+
tags:
53+
- phpstan.broker.dynamicStaticMethodReturnTypeExtension

extension.neon

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,6 @@ parameters:
99
- phpstan-bootstrap.php
1010
scanFiles:
1111
- %magentoRootPath%/app/Mage.php
12-
- %magentoRootPath%/app/code/core/Mage/Core/functions.php
13-
scanDirectories:
14-
#for static reflection, so we don't have to call autoloader
15-
- %magentoRootPath%/lib/
16-
- %magentoRootPath%/app/code/local/
17-
- %magentoRootPath%/app/code/community/
18-
- %magentoRootPath%/app/code/core/
1912
typeAliases:
2013
Mage_Catalog_Model_Entity_Product_Collection: 'Mage_Catalog_Model_Resource_Product_Collection'
2114
callback: 'callable'

phpstan-bootstrap-mage-autoload.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
declare(strict_types=1);
3+
4+
use PHPStanMagento1\Autoload\Magento\ModuleControllerAutoloader;
5+
6+
/**
7+
* @var $container \PHPStan\DependencyInjection\MemoizingContainer
8+
*/
9+
$magentoRootPath = $container->getParameter('magentoRootPath');
10+
if (empty($magentoRootPath)) {
11+
throw new \Exception('Please set "magentoRootPath" in your phpstan.neon.');
12+
}
13+
14+
if (!defined('BP')) {
15+
define('BP', $magentoRootPath);
16+
}
17+
18+
(new ModuleControllerAutoloader('local'))->register();
19+
(new ModuleControllerAutoloader('core'))->register();
20+
(new ModuleControllerAutoloader('community'))->register();
21+
22+
/**
23+
* We replace the original Varien_Autoload autoloader with a custom one in order to prevent errors with invalid classes
24+
* that are used throughout the Magento core code.
25+
* The original autoloader would in this case return false and lead to an error in phpstan because the type alias in extension.neon
26+
* is evaluated afterwards.
27+
*
28+
* @see \Varien_Autoload::autoload()
29+
*/
30+
spl_autoload_register(static function($className) {
31+
spl_autoload_unregister([Varien_Autoload::instance(), 'autoload']);
32+
33+
$classFile = str_replace(' ', DIRECTORY_SEPARATOR, ucwords(str_replace('_', ' ', $className)));
34+
$classFile .= '.php';
35+
36+
foreach (explode(':', get_include_path()) as $path) {
37+
if (\file_exists($path . DIRECTORY_SEPARATOR . $classFile)) {
38+
return include $classFile;
39+
}
40+
}
41+
}, true, true);

phpstan-bootstrap.php

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,6 @@
33

44
use PHPStanMagento1\Autoload\Magento\ModuleControllerAutoloader;
55

6-
if (!defined('DS')) {
7-
define('DS', DIRECTORY_SEPARATOR);
8-
}
9-
if (!defined('PS')) {
10-
define('PS', PATH_SEPARATOR);
11-
}
12-
136
/**
147
* @var $container \PHPStan\DependencyInjection\MemoizingContainer
158
*/
@@ -22,6 +15,15 @@
2215
define('BP', $magentoRootPath);
2316
}
2417

18+
define('staticReflection', true);
19+
20+
if (!defined('DS')) {
21+
define('DS', DIRECTORY_SEPARATOR);
22+
}
23+
if (!defined('PS')) {
24+
define('PS', PATH_SEPARATOR);
25+
}
26+
2527
/**
2628
* Set include path
2729
*/

src/Type/Mage/GetResourceModel.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55

66
final class GetResourceModel extends StaticMethodReturnTypeDetector
77
{
8+
/**
9+
* @throws \PHPStan\Broker\ClassNotFoundException
10+
*/
811
public function getMagentoClassName(string $identifier): string
912
{
1013
$className = $this->getMagentoConfig()->getResourceModelClassName($identifier);

0 commit comments

Comments
 (0)