Git Product home page Git Product logo

ray.compiler's People

Contributors

fiahfy avatar koriym avatar naokitsuchiya avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

ray.compiler's Issues

ScriptInjector 利用時の Ray.Di のビルトインモジュールの扱い

Ray.Di はビルトインモジュールとして以下の3つのモジュールをインストールしています。

  • AssistedModule
  • ProviderSetModule
  • MultiBindingModule

ref: https://github.com/ray-di/Ray.Di/blob/2.x/src/di/ContainerFactory.php#L22-L26

上記のモジュールは Ray\Di\Injector を利用する場合には利用側が意識する必要はありませんが、ScriptInjector を利用する場合には利用側でモジュールをインストールする必要があります。

ScriptInjector を利用する際にも通常利用側が意識しないような作りが望ましいと感じましたがどうでしょうか。

Feature Request or Question - support environment variable

Hi. Is there any way to support environment variable at runtime ?

Currently, BEAR.Sunday tutorial too refers PHP's getenv() function.

https://bearsunday.github.io/manuals/1.0/en/tutorial2.html

            new AuraSqlModule(
                (string) getenv('TKT_DB_DSN'),

But it is evaluated (compiled) at build system's environment value.

eg. I use Google Cloud Build for build (Docker container build & di compiled), and run application at Cloud Run.

Is there any way like PHP-DI 's env variable evaluation?
https://php-di.org/doc/php-definitions.html#environment-variables

AbstractInjectorContext 利用時に module を上書きできるようにする

AbstractInjectorContext はコンテキストに応じたモジュール、キャッシュプロバイダなどを提供します。

主にテスト実行時において、コンテキストは再利用しつつもテストケースに応じて束縛を変更したい場合があります。

上記のようなケースに対応するには、束縛を上書きするためのモジュールもしくはコンテキストを外から渡せる必要があります。

以下のようなイメージになります

$context = new TestContext($tmp, new OverrideModule());

$module = $context();

Uncaught TypeError

[error] "PHP message: PHP Fatal error: Uncaught TypeError: Argument 2 passed to Ray\Compiler\FunctionCode::__invoke() must implement interface Ray\Di\DependencyInterface, string given

Provider束縛で指定する型がInterfaceでない場合、指定した型の依存解決が必要となりUnbound例外が発生する。

Bug Report

Provider束縛で指定する型がInterfaceでない場合、指定した型の依存解決が必要となりUnbound例外が発生する。

How to reproduce

<?php

declare(strict_types=1);

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

class A
{
    public function __construct(private B $b)
    {}
}

class B
{
    public function __construct(private C $c)
    {}
}

class C
{
    public function __construct(private DInterface $d)
    {}
}

interface DInterface {}

class D implements DInterface {}

class Provider implements \Ray\Di\ProviderInterface
{
    public function get(): B
    {
        return new B(new C(new D()));
    }
}

class Module extends \Ray\Di\AbstractModule
{
    protected function configure()
    {
        $this->bind(A::class);
        $this->bind(B::class)->toProvider(Provider::class);
    }
}

$module = new Module();
$compiler = new \Ray\Compiler\DiCompiler($module, __DIR__ . '/../tmp');
$compiler->compile();

このとき、C はコンパイル対象ではないことを期待していましたが、実際には以下のように Unbound 例外がスローされます。

Fatal error: Uncaught exception 'Ray\Di\Exception\Unbound' with message 'dependency 'DInterface' with name '' used in /Users/tsuchiya/work/github.com/NaokiTsuchiya/Ray.Compiler/tests/Fake/example.php:21 ($d)'

  thrown in /Users/tsuchiya/work/github.com/NaokiTsuchiya/Ray.Compiler/src/NodeFactory.php on line 118
PHP Fatal error:  Uncaught exception 'Ray\Di\Exception\Unbound' with message 'dependency 'DInterface' with name '' used in /Users/tsuchiya/work/github.com/NaokiTsuchiya/Ray.Compiler/tests/Fake/example.php:21 ($d)'

  thrown in /Users/tsuchiya/work/github.com/NaokiTsuchiya/Ray.Compiler/src/NodeFactory.php on line 118

Process finished with exit code 255

上記の Module を文字列評価した結果は以下のとおりです。

A- => (dependency) A
B- => (provider) (dependency) Provider
C- => (dependency) C

利用側でInterfaceを定義して回避することは可能ですが、
Bの依存クラスであるCがコンパイル対象となるのは期待する振る舞いではないように感じました。

その他

Red テストの実装は以下のとおりです。

https://github.com/ray-di/Ray.Compiler/compare/1.x...NaokiTsuchiya:untarget-provider?expand=1

同時アクセスで RuntimeException が発生する

以下のようなリクエストを同時に2つ出すと module.txt がないとして RuntimeError になることがあります。

curl http://localhost:8080/some/uri
{
    "message": "Service Unavailable",
    "logref": "4c75224c",
    "request": "get page://self/some/uri",
    "exceptions": "RuntimeException(/path/to/var/tmp/dev-hal-app/di/module.txt is not readable)",
    "file": "/path/to/vendor/ray/compiler/src/ScriptInjector.php(180)"
}

ScriptInjector::__wakeupScriptInjector::saveModule のファイルアクセスのタイミング問題で発生しているような気はしますが、解決策は何かありますでしょうか?

Problem with the optimization of Ray.Aop 2.7.1

問題

以下のようにbindingsが後になっているとsetTiresでバインディングがあるときに、つまりセッター人ジェクションにAOPが適用されているエッジケースに対応できない。

$instance = new \Ray_Compiler_FakeCar_JhUHY3Q($prototype('Ray\\Compiler\\FakeEngineInterface-'));
$instance->setTires($prototype('Ray\\Compiler\\FakeTyreInterface-'), 
$instance->bindings = array('setTires' => array($singleton('Ray\\Compiler\\FakeInterceptor-')));

$return $instance;

解決策

$instance->bindings =の代入をnewの直後に行う。

$instance = new \Ray_Compiler_FakeCar_JhUHY3Q($prototype('Ray\\Compiler\\FakeEngineInterface-'));
$instance->bindings = array('setTires' => array($singleton('Ray\\Compiler\\FakeInterceptor-')));
$instance->setTires($prototype('Ray\\Compiler\\FakeTyreInterface-'), 

$return $instance;

InjectorFactory and CachedInjectorFactory

Summary

The InjectorFactory and CachedInjectorFactory is the injector for when you want to sacrifice a little simplicity and get great performance.

Preparation:

You must have at least two modules, one for base and one for production. You can name them as you wish, but you must install DiCompileModule for production.

With the CachedInjectorFactory...

  • Ray.Di injector is 2X the performance during development and ScriptInjector has 10x more performance. CachedInjectorFactory creates either injector by context.

  • The CachedInjectorFactory caches the injector itself. which can contain bootstrap objects in singleton container.

  • The cost of the initial object injection becomes almost zero. This is usually the main factor that slows down the framework. CachedInjectorFactory dramatically improves bootstrap performance.

Usage

final class AppInjector
{
    /**
     * @param 'dev'|'prod' $context
     */
    private static function getInstance(string $context) : InjectorInterface
    {
        if ($context === 'dev') {
            return CachedInjectorFactory::getInstance(
                'dev',
                '/path/to/di/dev',
                function () : AbstractModule {
                    return new Module;
                }
            );
        }

        return CachedInjectorFactory::getInstance(
            'prod',
             '/path/to/di/prod',
            function () : AbstractModule {
                $module = new Module;
                $module->install(new DiCompileModule(true));

                return $module;
            },
            (new PhpFileCache('/path/to/injector_cache')),
            [RootObjectInterface::class] 
        );
    }
}

$context = getenv('context');
$injector = AppInjectpr::getInstance($context);
$root = $injector->getInstance(RootObjectInterface::class); // get cached object in the production

概要

InjectorFactoryは単純さが少し犠牲になりますが、大きなパフォーマンスが得られるインジェクターです。

準備:

モジュールを最低2つ、ベースのモジュールとプロダクション用のモジュールを用意します。名前は自由につけれますが、プロダクションではDiCompileModuleをインストールしてください。

CachedInjectorFactoryを使うと…

  • 開発時には速度の速いRay.Di injector、プロダクションで最高のパフォーマンスを発揮するRay.CompilerのScriptInjectorが渡されます。

  • 開発時のRay.Di injectorはScriptInjectorの倍以上のパフォーマンスがあり、プロダクションの時のScriptInjectorは10倍以上のパフォーマンスがあります。(環境によります)

  • CachedInjectorFactoryはインジェクターをキャッシュします。そのキャッシュされるインジェクターにはブートストラップの時に必要なオブジェクトがシングルトンが含まれます。

  • アプリケーションブート時のインジェクションコストがほぼゼロになります。通常これはフレームワークの速度を遅くしてる主要因です。CachedInjectorFactoryはブートストラップのパフォーマンスを劇的に改善します。

Wrong code generation for unbound interface dependencies

バインドされていないインターフェイスの依存のコードの作成が間違っている

生成例

<?php
  
namespace Ray\Di\Compiler;

$instance = new \FakeVendor\HelloWorld\UnboundInterface();
$is_singleton = false;
return $instance;

Unboundをインターフェイスを確認しないでUntarget束縛してるのではないだろうか?

State remains in container

Bug Report

CachedInjectorFactoryからインジェクターを取得した時にコンテナ内の状態変更がリセットされていない。

How to reproduce

$injector = ContextInjector::getInstance($context);
$deep = $injector->getInstance(FakeDeep::class);
// $deep状態変更 (FakeDeepはシングルトン)

$injector = ContextInjector::getInstance($context);
$deep2 = $injector->getInstance(FakeDeep::class);
// $deep2は$deepと同じ

遅延モジュールをシリアライズ可能に

現在のScriptInjectorの生成

$injector = new ScriptInjector(
    __DIR__ . '/tmp',
    static function () {
        return new FakeCarModule();
    }
);

改善案:

上記に対して、LazyModuleInterfaceを実装したモジュールを用意します。

interface LazyModuleInterface
{
    public function __invoke(): AbstractModule;
}
class MyLazyModule implemetes LazyModuleInterface
{
    public function __invoke(): AbstractModule
    {
        return new FakeCarModule();
    }
}
$injector = new ScriptInjector(
    __DIR__ . '/tmp',
    new MyLazyModule()
);

MyLazyModuleはシリアライズ可能なオブジェクトです。無名関数と違って、モジュールをデータファイル(_module.txt)に書き出す必要がなくrace conditionの問題が消滅します。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.