Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finalize on Magento 1 #87

Closed
joshua-bn opened this issue Feb 26, 2025 · 4 comments
Closed

Finalize on Magento 1 #87

joshua-bn opened this issue Feb 26, 2025 · 4 comments

Comments

@joshua-bn
Copy link

I just attempted to run finalize-classes on a Magento 1 install. PhpStan has >3000 errors like Class Zend_Session_SaveHandler_Exception extends final class Zend_Session_Exception. Perhaps the problem is the PSR-0 namespacing?

@TomasVotruba
Copy link
Member

Hi, working autoload is requirement for this tool to run.

Afaik Zend 1 has custom magic loading, that combines prefixes and short class name. I would not recommend to run this tool, untill you upgrade to newer Zend version with PSR-4.

@joshua-bn
Copy link
Author

I am using Composer's autoloader and everything is working fine. It's not an autoloader issue as PSR-0 and PSR-4 work fine. I am using a modified version of https://github.com/openmage

@joshua-bn
Copy link
Author

joshua-bn commented Feb 26, 2025

I haven't tested this, but this would support PSR-0:

<?php

declare (strict_types=1);
namespace Rector\SwissKnife\PhpParser\NodeVisitor;

use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt\Class_;
use PhpParser\NodeVisitorAbstract;
use ReflectionClass;
use ReflectionException;


final class ParentClassNameCollectingNodeVisitor extends NodeVisitorAbstract
{
    /**
     * @var string[]
     */
    private $parentClassNames = [];

    public function enterNode(Node $node) : ?Node
    {
        if (!$node instanceof Class_) {
            return null;
        }

        if (!$node->extends instanceof Name) {
            return null;
        }

        $this->parentClassNames[$node->extends->toString()] = true;

        return $node;
    }

    /**
     * @return string[]
     */
    public function getParentClassNames(): array
    {
        $filteredClassNames = array_filter(
            $this->parentClassNames,
            function (string $parentClassName): bool {
                // If it has underscores, it's likely PSR-0 userland code
                if (str_contains($parentClassName, '_')) {
                    return true;
                }

                // If it has a namespace separator, handle vendor filtering
                if (str_contains($parentClassName, '\\')) {
                    // Filter out vendor-specific namespaces
                    return !str_contains($parentClassName, 'Symfony\\')
                        && !str_contains($parentClassName, 'PHPStan\\')
                        && !str_contains($parentClassName, 'PhpParser\\');
                }

                // If it exists, check if it's a built-in PHP class (no file path)
                if (class_exists($parentClassName, true)) {
                    try {
                        $reflection = new ReflectionClass($parentClassName);
                        // Native PHP classes return empty string or false for getFileName()
                        $fileName = $reflection->getFileName();
                        return $fileName !== false && $fileName !== '';
                    } catch (ReflectionException) {
                        // If reflection fails, assume it's not userland code
                        return false;
                    }
                }

                // If it doesn't exist yet, assume it's userland code that needs autoloading
                return true;
            },
            ARRAY_FILTER_USE_KEY
        );

        ksort($filteredClassNames);

        return array_keys($filteredClassNames);
    }
}

@joshua-bn
Copy link
Author

// If reflection fails, assume it's not userland code this should probably do the opposite. If it fails, we probably just can't find the class because the autoloader doesn't know how to load it. In which case, we shouldn't consider it. Or, throw an exception because it can't figure out what to do about it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants