php-scoper icon indicating copy to clipboard operation
php-scoper copied to clipboard

[Scoper] Add polyfill support

Open tntrex opened this issue 5 years ago • 10 comments

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 <[email protected]>
*
* 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 <[email protected]>
*
* 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\\*',
   ],
];

tntrex avatar Nov 25 '20 15:11 tntrex

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 avatar Dec 01 '20 08:12 discordier

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.

discordier avatar Dec 01 '20 12:12 discordier

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)
    ),
];

tntrex avatar Dec 01 '20 12:12 tntrex

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?

discordier avatar Dec 01 '20 13:12 discordier

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

theofidry avatar Dec 01 '20 17:12 theofidry

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

marekdedic avatar Mar 10 '21 09:03 marekdedic

Fixed it within PHP-Scoper this way https://github.com/humbug/php-scoper/pull/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

theofidry avatar May 17 '21 21:05 theofidry

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.

JoshuaBehrens avatar Aug 15 '21 00:08 JoshuaBehrens

Box has not been patched yet IIRC, but it shouldn’t be too hard to do so

On Sun 15 Aug 2021 at 02:57, Joshua Behrens @.***> wrote:

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.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/humbug/php-scoper/issues/440#issuecomment-898978164, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABHPVAPMRIRQKBAFKDTSVGLT44GIVANCNFSM4UCSSWCA . Triage notifications on the go with GitHub Mobile for iOS https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675 or Android https://play.google.com/store/apps/details?id=com.github.android&utm_campaign=notification-email .

theofidry avatar Aug 18 '21 11:08 theofidry

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

JoshuaBehrens avatar Aug 19 '21 11:08 JoshuaBehrens

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.

theofidry avatar Nov 12 '22 08:11 theofidry