Skip to content

Exporting closure containing self leads to fatal error #26

@boesing

Description

@boesing

Hey there,

I have the following (reduced) example of our application which uses this component to dump the application config to a filesystem cache:

<?php

use Brick\VarExporter\VarExporter;

require __DIR__ . '/vendor/autoload.php';

$dataProvider = new class {
    public const CONFIGURATION_ENTRY = 'data-provider-specific-config';

    public function getConfig(): array
    {
        return [
            self::CONFIGURATION_ENTRY => [
                'foo' => 'bar',
            ],
            'factories' => [
                'MyService' => static function (array $config): object {
                    $configForMyDataProvider = $config[self::CONFIGURATION_ENTRY];

                    return new class ($configForMyDataProvider['foo']) {

                        public string $foo;

                        public function __construct(string $foo)
                        {
                            $this->foo = $foo;
                        }
                    };
                },
            ],
        ];
    }
};

$config = array_merge(
    [],
    $dataProvider->getConfig(),
    // Other data providers providing stuff
);

$content = "<?php\n" . VarExporter::export(
    $config,
    VarExporter::ADD_RETURN | VarExporter::CLOSURE_SNAPSHOT_USES
);

file_put_contents('cached-config.php', $content);

$configFromFilesystem = require 'cached-config.php';

($configFromFilesystem['factories']['MyService'])($configFromFilesystem);

So the exporter generates this code:

<?php
return [
    'data-provider-specific-config' => [
        'foo' => 'bar'
    ],
    'factories' => [
        'MyService' => static function (array $config) : object {
            $configForMyDataProvider = $config[self::CONFIGURATION_ENTRY];
            return new class($configForMyDataProvider['foo'])
            {
                public string $foo;
                public function __construct(string $foo)
                {
                    $this->foo = $foo;
                }
            };
        }
    ]
];

Overall, no real problem and everything works until the closure is being used to instantiate the service. PHP gives us the follow fatal error:

Fatal error: Uncaught Error: Cannot access self:: when no class scope is active in /project/cached-config.php:8

I wonder if it is possible to convert the self reference to some kind of FQCN so that we do not have to care about using self or not.

I am willing to contribute a fix. Just wanted to raise the issue first.

Feel free to give me some feedback whenever you find some time.
Thanks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions