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

[Scoper] Add polyfill support #440

Closed
hustlahusky opened this issue Nov 25, 2020 · 11 comments
Closed

[Scoper] Add polyfill support #440

hustlahusky opened this issue Nov 25, 2020 · 11 comments

Comments

@hustlahusky
Copy link

Bug report

Question Answer
Box version 0.13.9
PHP version 7.3.22
Platform with version Alpine (docker)
Github Repo -

Function aliasing described in docs seems not working with symfony polyfills functions. File scoped by namespace, but not function_exist check, also no aliases in scoper-autoload.php.

Can this caused because they all are oneliners? For example, dd function from symfony/var-dumper prefixed and aliased as expected.

Original vendor/symfony/polyfill-php80/bootstrap.php
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

use Symfony\Polyfill\Php80 as p;

if (PHP_VERSION_ID >= 80000) {
   return;
}

if (!defined('FILTER_VALIDATE_BOOL') && defined('FILTER_VALIDATE_BOOLEAN')) {
   define('FILTER_VALIDATE_BOOL', FILTER_VALIDATE_BOOLEAN);
}

if (!function_exists('fdiv')) {
   function fdiv(float $num1, float $num2): float { return p\Php80::fdiv($num1, $num2); }
}
if (!function_exists('preg_last_error_msg')) {
   function preg_last_error_msg(): string { return p\Php80::preg_last_error_msg(); }
}
if (!function_exists('str_contains')) {
   function str_contains(string $haystack, string $needle): bool { return p\Php80::str_contains($haystack, $needle); }
}
if (!function_exists('str_starts_with')) {
   function str_starts_with(string $haystack, string $needle): bool { return p\Php80::str_starts_with($haystack, $needle); }
}
if (!function_exists('str_ends_with')) {
   function str_ends_with(string $haystack, string $needle): bool { return p\Php80::str_ends_with($haystack, $needle); }
}
if (!function_exists('get_debug_type')) {
   function get_debug_type($value): string { return p\Php80::get_debug_type($value); }
}
if (!function_exists('get_resource_id')) {
   function get_resource_id($res): int { return p\Php80::get_resource_id($res); }
}
Prefixed one
<?php

namespace _PhpScoper07cbd2d8c7e4;

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use _PhpScoper07cbd2d8c7e4\Symfony\Polyfill\Php80 as p;
if (\PHP_VERSION_ID >= 80000) {
   return;
}
if (!\defined('FILTER_VALIDATE_BOOL') && \defined('FILTER_VALIDATE_BOOLEAN')) {
   \define('FILTER_VALIDATE_BOOL', \FILTER_VALIDATE_BOOLEAN);
}
if (!\function_exists('fdiv')) {
   function fdiv(float $num1, float $num2) : float
   {
       return \_PhpScoper07cbd2d8c7e4\Symfony\Polyfill\Php80\Php80::fdiv($num1, $num2);
   }
}
if (!\function_exists('preg_last_error_msg')) {
   function preg_last_error_msg() : string
   {
       return \_PhpScoper07cbd2d8c7e4\Symfony\Polyfill\Php80\Php80::preg_last_error_msg();
   }
}
if (!\function_exists('str_contains')) {
   function str_contains(string $haystack, string $needle) : bool
   {
       return \_PhpScoper07cbd2d8c7e4\Symfony\Polyfill\Php80\Php80::str_contains($haystack, $needle);
   }
}
if (!\function_exists('str_starts_with')) {
   function str_starts_with(string $haystack, string $needle) : bool
   {
       return \_PhpScoper07cbd2d8c7e4\Symfony\Polyfill\Php80\Php80::str_starts_with($haystack, $needle);
   }
}
if (!\function_exists('str_ends_with')) {
   function str_ends_with(string $haystack, string $needle) : bool
   {
       return \_PhpScoper07cbd2d8c7e4\Symfony\Polyfill\Php80\Php80::str_ends_with($haystack, $needle);
   }
}
if (!\function_exists('get_debug_type')) {
   function get_debug_type($value) : string
   {
       return \_PhpScoper07cbd2d8c7e4\Symfony\Polyfill\Php80\Php80::get_debug_type($value);
   }
}
if (!\function_exists('get_resource_id')) {
   function get_resource_id($res) : int
   {
       return \_PhpScoper07cbd2d8c7e4\Symfony\Polyfill\Php80\Php80::get_resource_id($res);
   }
}
scoper.inc.php
<?php

declare(strict_types=1);

use Isolated\Symfony\Component\Finder\Finder;

return [
   'finders' => [
       Finder::create()
           ->files()
           ->in([
               __DIR__ . '/resources',
               __DIR__ . '/src',
           ]),
       Finder::create()
           ->files()
           ->ignoreVCS(true)
           ->notName('/LICENSE|.*\\.md|.*\\.dist|Makefile|composer\\.json|composer\\.lock/')
           ->exclude([
               'doc',
               'test',
               'test_old',
               'tests',
               'Tests',
               'vendor-bin',
           ])
           ->in(__DIR__ . '/vendor'),
       Finder::create()->append([
           'bin/apidoc',
           'composer.json',
       ]),
   ],
   'whitelist' => [
       'spaceonfire\\ApiDoc\\*',
       'Composer\\Autoload\\*',
   ],
];
@discordier
Copy link
Contributor

I can confirm this.

The problem is, how shall we approach this from within scoper?

Quick workaround, add the following to your scoper.inc.php

<?php

declare(strict_types=1);

use Isolated\Symfony\Component\Finder\Finder;

$symfonyPolyfills = (static function (): array {
    $files = [];
    foreach (
        Finder::create()
            ->files()
            ->in(__DIR__ . '/vendor/symfony/polyfill-*')
            ->name('bootstrap.php') as $bootstrap
    ) {
        $files[] = $bootstrap->getPathName();
    }

    return $files;
})();

return [
    'whitelist' => [
        '\Phpcq\PluginApi\*'
    ],
    'files-whitelist' => $symfonyPolyfills,
];

@discordier
Copy link
Contributor

Scratch my last comment, this results in the bootstrap files not being scoped but the classes implementing the polyfills are still scoped. So this is only half of the way to go.

The scoper should emit classes/functions from whitelisted files "as is" while still changing scoped class usage within.
This is apparently not implemented yet.

@hustlahusky
Copy link
Author

Scratch my last comment, this results in the bootstrap files not being scoped but the classes implementing the polyfills are still scoped. So this is only half of the way to go.

In addition to workaround Symfony\Polyfill namespace should be also whitelisted like this:

<?php

declare(strict_types=1);

use Isolated\Symfony\Component\Finder\Finder;

$polyfillsBootstrap = Finder::create()
    ->files()
    ->in(__DIR__ . '/vendor/symfony/polyfill-*')
    ->name('bootstrap.php');

return [
    'whitelist' => [
        'spaceonfire\\ApiDoc\\*',
        'Symfony\\Polyfill\\*',
    ],
    'files-whitelist' => array_map(
        static function ($file) {
            return $file->getPathName();
        },
        iterator_to_array($polyfillsBootstrap)
    ),
];

@discordier
Copy link
Contributor

You are right, I also stumbled upon that one also.

However, I feel we should address the root cause some how.
What do you think might be the best approach?

@theofidry theofidry changed the title Function aliasing not working with symfony polyfills Add polyfill support Dec 1, 2020
@theofidry
Copy link
Member

I'm not too sure yet how this should be handled to be honest. A few ideas & notes:

  • How to detect a polyfill? Should it be convention based (on the package name)? Passable via the config? (if via the config there can be a few default ones)
  • Can this be done in one scoping process? For example by knowing what is being polyfilled we could correct some scoping or add the appropriate aliases. Or maybe this should be another scoping process with a different configuration

@marekdedic
Copy link
Contributor

Hi,
I recently stumbled upon this as well, my solution is the following:
https://github.com/skaut/skaut-google-drive-gallery/blob/824202615bf397aae03d5be0fd74f0679b483507/scoper.inc.php#L44-L46

This works just fine for me, however, I'm using php-scoper with #457 and #460

@theofidry
Copy link
Member

Fixed it within PHP-Scoper this way #481; thanks all for the leads.

As we are all aware though, this is but a workaround. I am however not too sure how we could fix this yet

@JoshuaBehrens
Copy link

We stumbled upon this as well, when we tried to box a laravel zero application under php 7.4 but the box.phar requires php 8 as the get_debug_type gets the global namespace and the polyfills are scoped far far away.

@theofidry
Copy link
Member

theofidry commented Aug 18, 2021 via email

@JoshuaBehrens
Copy link

So there is no pul request on box yet about it? 💭

@theofidry
Copy link
Member

A doc entry has been added since then: https://github.com/humbug/php-scoper/blob/main/docs/further-reading.md#polyfills and with the new upcoming release this should also be drastically simper.

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

No branches or pull requests

5 participants