laminas / laminas-zendframework-bridge

Alias legacy ZF class names to Laminas Project equivalents.
BSD 3-Clause "New" or "Revised" License
1.19k stars 21 forks source link

Unable to use with PHP 7.4 preload #49

Closed thomasvargiu closed 4 years ago

thomasvargiu commented 4 years ago

The current behaviour doesn't allow to use the new PHP 7.4 preload. It's useful for laminas-mvc application to preload all laminas-* classes, but right now the autoloader can't register the aliases because the laminas classes are already loaded.

I don't know how to solve it, but probably it can be useful to have a function where we can provide a list of classes (maybe from composer's autoload_classmap.php) and trying to register all aliases from Zend to Laminas. This function can be called in the application bootstrap. Honestly I don't know if this solution can be useful because the application should register all aliases, even if they are not used.

froschdesign commented 4 years ago

@thomasvargiu This component is only intended for temporary use and it should not be used in other libraries. A complete migration should solve the problem.

thomasvargiu commented 4 years ago

Thank you @froschdesign. I agree, but some big projects uses libraries that they didn't know when (end if) will be migrated.

If someone is interested, this is a simple script to write aliases of preloaded classes, and it should be called before to include the composer autoloader (this is just an experiment).

$cacheFile = __DIR__  . '/data/cache/preload_classes.php';

$classesToLoad = null;

if (file_exists($cacheFile)) {
    $classesToLoad = include $cacheFile;
}

if (! is_array($classesToLoad)) {
    $classesToLoad = [];

    $status = opcache_get_status() ?: [];
    $classes = $status['preload_statistics']['classes'] ?? [];
    require_once __DIR__ . '/vendor/laminas/laminas-zendframework-bridge/src/RewriteRules.php';
    $namespaces = \Laminas\ZendFrameworkBridge\RewriteRules::namespaceReverse();

    foreach ($classes as $class) {
        $segments = explode('\\', $class);

        $i = 0;
        $check = '';

        while (isset($segments[$i + 1], $namespaces[$check . $segments[$i] . '\\'])) {
            $check .= $segments[$i] . '\\';
            ++$i;
        }

        if ($check === '') {
            continue;
        }

        $legacy = $namespaces[$check]
            . strtr(substr($class, strlen($check)), [
                'ApiTools' => 'Apigility',
                'Mezzio' => 'Expressive',
                'Laminas' => 'Zend',
            ]);

        if (class_exists($legacy) || interface_exists($legacy) || trait_exists($legacy)) {
            continue;
        }

        $classesToLoad[$class] = $legacy;
    }

    file_put_contents($cacheFile, sprintf('<?php return %s;', var_export($classesToLoad, true)));
}

foreach ($classesToLoad as $class => $alias) {
    if (class_exists($alias) || interface_exists($alias) || trait_exists($alias)) {
        continue;
    }

    class_alias($class, $alias);
}