PHPでのコード依存管理(大量のComponentテクニックが襲来)

11823 ワード

記事は専門のLaravel開発者コミュニティから転送され、元のリンク:https://learnku.com/laravel/t...
PHPのアプリケーションまたはライブラリを作成する場合、通常は3つの依存関係があります.
  • ハード依存性:
  • を正常に実行するには、アプリケーション/ライブラリが必要です.
  • オプションの依存関係:例えば、PHPライブラリは、異なるフレームワークに機能
  • を提供することができる.
  • 開発依存:デバッグツール、テストフレームワークなど...

  • これらの依存関係をどのように管理しますか?
    ハード依存性:
    
    
    {  
        "require": {  
            "acme/foo": "^1.0"  
        }  
    }
    

    オプションの依存関係:
    
    
    {  
        "suggest": {  
            "monolog/monolog": "Advanced logging library",  
            "ext-xml": "Required to support XML"  
        }  
    }
    

    開発依存度:
    
    
    {  
        "require-dev": {  
          "monolog/monolog": "^1.0",  
          "phpunit/phpunit": "^6.0"  
        }  
    }
    

    今のところ順調です.では、どこが間違っているのでしょうか.主にrequire-devに一定の制限があります.
    問題と制限
    過多な依存関係
    パッケージマネージャを使用して依存を解決するのは非常に良いです.この方法はコードをよく更新し再利用することができる.しかし、どのバッグを導入したのか、どのバッグを導入したのかに責任を負わなければなりません.あなたが導入したこれらのパッケージは、バグや安全ではないリスクがあります.サードパーティの問題に悩まされているほか、他の人が書いたものに頼っているようになり、これらのものはコントロールできないかもしれません.PackagistとGitHubはこれらのリスクを減らすために良い仕事をしたが、リスクは依然として存在している.JavaScriptコミュニティでleft-pad fiascoは良い例であり、パッケージを追加することは完全に影響しないわけではありません.エラーが発生するためです.
    依存する2つ目の問題は、互換性が必要であることです.これはComposerの仕事です.しかし、Composerは、同時にインストールできない依存があり、依存を追加するほど競合する可能性があります.
    段落が長いと思います.ここを直接見てください.あなたが導入した依存に責任を負い、依存を少なくします.
    強い関係の衝突
    次の例を見てみましょう.
    
    
    {  
        "require-dev": {  
            "phpstan/phpstan": "^1.0@dev",  
            "phpmetrics/phpmetrics": "^2.0@dev"  
        }  
    }
    

    この2つのパッケージは静的解析ツール(static analysis tools)であり、同時にインストールすることはできない.すなわち、異なる互換性のないPHP-Parserバージョンに依存しているため、衝突が発生した.
    これは「愚かな_」と呼ぶことができる.衝突:既存のアプリケーションと互換性のない依存を含めようとすると、衝突が発生します.この2つのパッケージは互いに互換性を持つ必要はありません.あなたのアプリケーションは直接彼らを使用することはありません.彼らはあなたのアプリケーションコードを実行することはありません.
    もう1つの例はSymfonyとLaravelの接続ライブラリを書いたことです.SymfonyとLaravelの2つの依存性を含めて接続をテストしたいと思っています.
    
    
    {  
        "require-dev": {  
            "symfony/framework-bundle": "^4.0",  
            "laravel/framework": "~5.5.0" # gentle reminder that Laravel  
                                          # packages are not semver  
        }  
    }
    

    場合によっては仕事をするかもしれないが、ほとんどの場合失敗する可能性が高い.このシーンは少し馬鹿かもしれません.同じ時間にこの2つのパッケージを同時に含めることはできません.このシーンをサポートすることはできません.
    テストできない依存関係
    composer.jsonを参照してください.
    
    
    {  
        "require": {  
            "symfony/yaml": "^2.8 || ^3.0"  
        },  
        "require-dev": {  
            "symfony/yaml": "^3.0"  
        }  
    }
    

    上記の例では、特定のバージョンのSymfony YAMLコンポーネントのみがインストール可能である(利用可能なsymfony/yamlパッケージバージョンは[3.0.0, 4.0.0[である.
    1つのアプリケーションでは、ほとんどの場合、これらに関心を持つ必要はありません.しかし、コンポーネントライブラリとしては問題かもしれません.実際には、コンポーネントライブラリでsymfony/yaml [2.8.0, 3.0.0[をテストできないことを意味します.
    これは確かに問題であるかどうかは、あなたの状況に大きくかかっています.このような状況が発生する可能性があり、それを根絶する有効な方法がないことを知っておく必要があります.上記の例は簡単ですが、このsymfony / yaml:^ 3.0が依存関係ツリーにより深く隠されている場合、例えば:
    
        
    {  
        "require": {  
            "symfony/yaml": "^2.8 || ^3.0"  
        },  
        "require-dev": {  
            "acme/foo": "^1.0"  # requires symfony/yaml ^3.0  
        }  
    }
    

    少なくとも今は君には分からない.
    ソリューション
    依存パッケージを使用しない
    親、大丈夫です.結局、あなたは本当にこの依存バッグを必要としません.
    PHARs
    PHARs(PHPファイル)は、アプリケーションを単一のファイルにパッケージ化する方法です.もっと知りたい場合は、PHP公式サイトを参照することをお勧めします.
    これを例にとると、PhpMetricsは静的解析ツールです.
       $ wget  -o phpmetrics.phar
       
       
       $ chmod +x phpmetrics.phar  
       $ mv phpmetrics.phar /usr/local/bin/phpmetrics  
       $ phpmetrics --version  
       PhpMetrics, version 1.9.0
       
       
       # or if you want to keep the PHAR close and do not mind the .phar  
       # extension:
       
       
       $ phpmetrics.phar --version  
       PhpMetrics, version 1.9.0

    警告:コードをPHARにパッケージするのはJavaのJARsのようにコードを隔離するものではありませんが、それでも開発中のプロジェクトPHP-Scoperがこの問題を解決しています.
    次に栗を挙げてこの問題を説明しましょう.コンソールアプリケーションmyapp.pharを構築し、Symfony YAML 2.8.0に依存して所定のPHPスクリプトを実行します.
        
        $ myapp.phar myscript.php

    スクリプトmyscript.phpは、Composerによって導入されたSymfony YAML 4.0.0を使用しています.
    PHARがSymfony YAMLクラスをロードした可能性があります.たとえば、SymfonyYamlYamlがスクリプトを実行し、スクリプトもSymfonyYamlYamlに依存していますが、このクラスはすでにロードされています.この問題は、スクリプトに必要なsymfony / yaml 2.8.0ではなく、4.0.0というパッケージをロードすることです.そのため、APIが異なると、これは打破しにくい.
    TL:DR; PHARsはPhpStanやPhpMetricsのような静的解析ツールによく適応しているが、いくつかの依存性の衝突により、コードの実行がそれほど信頼できなくなる(少なくとも現在はそうである!)
    PHARを使用するときは、他にも覚えておく必要があります.
  • は、Corposerではそれらに対するオリジナルのサポートがないため、追跡が困難である.しかし、このComposerプラグインtooly-composer-scriptやPhiVeのPHARインストーラ
  • などのソリューションがあります.
  • でバージョンをどのように管理するかは、プロジェクトによって異なります.一部のプロジェクトでは、異なる安定したチャネルを持つ「自己更新」コマンドが提供され、一部のプロジェクトでは独自のダウンロードエンドポイントと最新バージョンが提供され、一部のプロジェクトではGitHubリリース版が使用され、各バージョンにPHARがリリースされています.

  • 複数のリポジトリの使用
    これまで最も流行した技術の一つです.したがって,1つのcomposer.jsonですべてのブリッジ依存関係を要求する必要はなく,このパケットを複数のリポジトリに分解する.
    前の例をacme/fooと呼ぶと、Symfonyのために別のパッケージacme/foo-bundleを作成し、Laravelのためにacme/foo-providerを作成します.
    すべてのものは実際には単一のリポジトリに保存でき、Symfonyのような他のパッケージの読み取り専用リポジトリしかありません.
    この方法の主な利点は,Symfony,Laravel,PhpBBなどの最終リポジトリ割り当て器のような追加のツールを必要としない比較的簡単であることである.欠点は、1つではなく複数のパッケージを維持していることです.
    構成の調整
    もう1つの方法は、より高度なインストールとテストスクリプトを使用することです.前の例と比較して、私たちは他のことをすることができます.
    
    
    #!/usr/bin/env bash  
    # bin/tests.sh
    
    
    #        
    vendor/bin/phpunit --exclude-group=laravel,symfony
    
    
    #    Symfony   
    composer require symfony/framework-bundle:^4.0  
    vendor/bin/phpunit --group=symfony  
    composer remove symfony/framework-bundle
    
    
    #    Laravel     
    composer require laravel/framework:~5.5.0  
    vendor/bin/phpunit --group=symfony  
    composer remove laravel/framework
    

    私の経験では、それは有効ですが、これは肥大化したテストスクリプトを招き、実行中は比較的遅く、メンテナンスが難しく、新しい貢献者にもあまり友好的ではありません.
    複数のcomposerを使用します.json
    この方法は比較的新しい(PHPでは)ものであり,主に必要なツールが既製ではないため,このソリューションでさらに説明する.
    この考え方は簡単です.例えば、下のほうです.
        {  
            "autoload": {...},  
            "autoload-dev": {...},
        
        
            "require": {...},  
            "require-dev": {  
                "phpunit/phpunit": "^6.0",  
                "phpstan/phpstan": "^1.0@dev",  
                "phpmetrics/phpmetrics": "^2.0@dev"  
            }  
        }
    phpstan/phpstanphpmetrics/phpmetricsをインストールし、異なるcomposer.jsonファイルを使用します.しかし、これはまず疑問があります.私たちはそれらをどこに置きますか?どの構造を採用していますか.
    composer-bin-pluginは運に応じて生まれた.非常に簡単なComposerプラグインで、composer.jsonと異なるディレクトリで対話できます.composer.json本のファイルがあると仮定します
        {  
            "autoload": {...},  
            "autoload-dev": {...},
        
        
            "require": {...},  
            "require-dev": {  
                "phpunit/phpunit": "^6.0"  
            }  
        }

    このプラグインをインストールできます.
        $ composer require --dev bamarni/composer-bin-plugin

    プラグインがインストールされ、composer bin acme smthを実行するたびに、サブディレクトリvendor-bin / acmecomposer smthコマンドが実行されます.PhpStanとPhpMetricsをこのようにインストールできます.
       
       $ composer bin phpstan require phpstan/phpstan:^1.0@dev  
       $ composer bin phpmetrics require phpmetrics/phpmetrics:^2.0@dev

    これにより、次のディレクトリ構造が作成されます.
        ... # projects files/directories  
        composer.json  
        composer.lock  
        vendor/  
        vendor-bin/  
            phpstan/  
                composer.json  
                composer.lock  
                vendor/  
            phpmetrics/  
                composer.json  
                composer.lock  
                vendor/

    そのうちvendor-bin / phpstan / composer.jsonはこのように見えます.
        {  
            "require": {  
                "phpstan/phpstan": "^1.0"  
            }  
        }
    vendor-bin/phpmetrics/composer.jsonはこう見えます
        {  
            "require": {  
                "phpmetrics/phpmetrics": "^2.0"  
            }  
        }

    したがって、vendor-bin / phpstan / vendor / bin / phpstanおよびvendor-bin / phpmetrics / vendor / bin / phpstanを呼び出して、PhpStanおよびPhpMetricsを簡単に使用することができます.
    さらに、異なるフレームワークでのライブラリの参照を例に挙げます.
        {  
            "autoload": {...},  
            "autoload-dev": {...},
        
        
            "require": {...},  
            "require-dev": {  
                "phpunit/phpunit": "^6.0",  
                "symfony/framework-bundle": "^4.0",  
                "laravel/framework": "~5.5.0"  
            }  
        }

    したがって、Symfonyが参照しているvendor-bin/symfony/composer.jsonのファイルと同じです.
        {  
            "autoload": {...},  
            "autoload-dev": {...},
        
        
            "require": {...},  
            "require-dev": {  
                "phpunit/phpunit": "^6.0",  
                "symfony/framework-bundle": "^4.0"  
            }  
        }

    Laravelが参照するvendor-bin/laravel/composer.jsonファイル:
        {  
            "autoload": {...},  
            "autoload-dev": {...},
        
        
            "require": {...},  
            "require-dev": {  
                "phpunit/phpunit": "^6.0",  
                "laravel/framework": "~5.5.0"  
            }  
        } 

    私たちの根composer.jsonは今こうなっているはずです.
        {  
            "autoload": {...},  
            "autoload-dev": {...},
        
        
            "require": {...},  
            "require-dev": {  
                "bamarni/composer-bin-plugin": "^1.0"  
                "phpunit/phpunit": "^6.0"  
            }  
        }

    コアライブラリ間の参照関係をテストするには、それぞれautoload.php(Symfonyの参照ファイルvendor-bin/symfony/vendor/autoload.phpなど)を持つ3つの異なるユニットテストファイルを作成する必要があります.
    本当にやってみると、この方法の主な欠点は冗長構成です.ルートプロファイルcomposer.jsonを他の2つのvendor-bin/{symfony,laravel}/composer.jsonに繰り返す必要があることを確認し、新しい依存が必要な場合は、他のcomposer.jsonに含める必要があります.これは制御不能なのでcomposer-inheritance-pluginが現れました.
    この小さなパッケージプラグインcomposer-merge-pluginは、vendor-bin/symfony/composer.jsonの内容をルートcomposer.jsonに統合します.次のようなものではありません
    
    
    {  
        "autoload": {...},  
        "autoload-dev": {...},
    
    
        "require": {...},  
        "require-dev": {  
            "phpunit/phpunit": "^6.0",  
            "symfony/framework-bundle": "^4.0"  
        }  
    }
    

    今はこうです.
    
    
    {  
        "require-dev": {  
            "symfony/framework-bundle": "^4.0",  
            "theofidry/composer-inheritance-plugin": "^1.0"  
        }  
    }
    

    他の構成では、自動ロードおよび依存はルートcomposer.jsonに含まれる.構成されていません.composer-inheritance-pluginは、composer-bin-pluginを使用して事前に構成される痩せたパッケージcomposer-merge-pluginです.
    インストールに必要な依存関係を確認できます.
    
    $ composer bin symfony show
    

    私はaliceのような多くのプロジェクトでこの方法を用い,PhpStanやPHP−CS−Fixerのような静的解析ツールやフレームブリッジとは異なる.もう1つの例はalice-data-fixturesであり、その中には多くの異なるORMブリッジ持続層(Doctrine ORM、Doctrine ODM、Eloquent ORMなど)とフレームワークの統合がある.
    pharsに代わるもう一つのツールとして、私は複数のプライベートプロジェクトでそれを使用し、よく働いています.
    結論
    変な方法を見つけたり、お勧めしない人もいると信じています.ここでの目標は、特定のものを判断したり推薦したりすることではなく、いくつかの依存関係、および各依存関係の利点と欠点を管理するための可能な方法をリストすることです.だから、あなたの質問とあなたの個人的な好みによって、あなたに最適なものを選んでください.人々が言ったように、解決策はなく、バランスしかない.