PHPでのコード依存管理(大量のComponentテクニックが襲来)
記事は専門のLaravel開発者コミュニティから転送され、元のリンク:https://learnku.com/laravel/t...
PHPのアプリケーションまたはライブラリを作成する場合、通常は3つの依存関係があります.ハード依存性: を正常に実行するには、アプリケーション/ライブラリが必要です.オプションの依存関係:例えば、PHPライブラリは、異なるフレームワークに機能 を提供することができる.開発依存:デバッグツール、テストフレームワークなど...
これらの依存関係をどのように管理しますか?
ハード依存性:
オプションの依存関係:
開発依存度:
今のところ順調です.では、どこが間違っているのでしょうか.主に
問題と制限
過多な依存関係
パッケージマネージャを使用して依存を解決するのは非常に良いです.この方法はコードをよく更新し再利用することができる.しかし、どのバッグを導入したのか、どのバッグを導入したのかに責任を負わなければなりません.あなたが導入したこれらのパッケージは、バグや安全ではないリスクがあります.サードパーティの問題に悩まされているほか、他の人が書いたものに頼っているようになり、これらのものはコントロールできないかもしれません.PackagistとGitHubはこれらのリスクを減らすために良い仕事をしたが、リスクは依然として存在している.JavaScriptコミュニティでleft-pad fiascoは良い例であり、パッケージを追加することは完全に影響しないわけではありません.エラーが発生するためです.
依存する2つ目の問題は、互換性が必要であることです.これはComposerの仕事です.しかし、Composerは、同時にインストールできない依存があり、依存を追加するほど競合する可能性があります.
段落が長いと思います.ここを直接見てください.あなたが導入した依存に責任を負い、依存を少なくします.
強い関係の衝突
次の例を見てみましょう.
この2つのパッケージは静的解析ツール(static analysis tools)であり、同時にインストールすることはできない.すなわち、異なる互換性のないPHP-Parserバージョンに依存しているため、衝突が発生した.
これは「愚かな_」と呼ぶことができる.衝突:既存のアプリケーションと互換性のない依存を含めようとすると、衝突が発生します.この2つのパッケージは互いに互換性を持つ必要はありません.あなたのアプリケーションは直接彼らを使用することはありません.彼らはあなたのアプリケーションコードを実行することはありません.
もう1つの例はSymfonyとLaravelの接続ライブラリを書いたことです.SymfonyとLaravelの2つの依存性を含めて接続をテストしたいと思っています.
場合によっては仕事をするかもしれないが、ほとんどの場合失敗する可能性が高い.このシーンは少し馬鹿かもしれません.同じ時間にこの2つのパッケージを同時に含めることはできません.このシーンをサポートすることはできません.
テストできない依存関係
例
上記の例では、特定のバージョンのSymfony YAMLコンポーネントのみがインストール可能である(利用可能な
1つのアプリケーションでは、ほとんどの場合、これらに関心を持つ必要はありません.しかし、コンポーネントライブラリとしては問題かもしれません.実際には、コンポーネントライブラリで
これは確かに問題であるかどうかは、あなたの状況に大きくかかっています.このような状況が発生する可能性があり、それを根絶する有効な方法がないことを知っておく必要があります.上記の例は簡単ですが、この
少なくとも今は君には分からない.
ソリューション
依存パッケージを使用しない
親、大丈夫です.結局、あなたは本当にこの依存バッグを必要としません.
PHARs
PHARs(PHPファイル)は、アプリケーションを単一のファイルにパッケージ化する方法です.もっと知りたい場合は、PHP公式サイトを参照することをお勧めします.
これを例にとると、PhpMetricsは静的解析ツールです.
警告:コードをPHARにパッケージするのはJavaのJARsのようにコードを隔離するものではありませんが、それでも開発中のプロジェクトPHP-Scoperがこの問題を解決しています.
次に栗を挙げてこの問題を説明しましょう.コンソールアプリケーション
スクリプト
PHARがSymfony YAMLクラスをロードした可能性があります.たとえば、
TL:DR; PHARsはPhpStanやPhpMetricsのような静的解析ツールによく適応しているが、いくつかの依存性の衝突により、コードの実行がそれほど信頼できなくなる(少なくとも現在はそうである!)
PHARを使用するときは、他にも覚えておく必要があります.は、Corposerではそれらに対するオリジナルのサポートがないため、追跡が困難である.しかし、このComposerプラグインtooly-composer-scriptやPhiVeのPHARインストーラ などのソリューションがあります.でバージョンをどのように管理するかは、プロジェクトによって異なります.一部のプロジェクトでは、異なる安定したチャネルを持つ「自己更新」コマンドが提供され、一部のプロジェクトでは独自のダウンロードエンドポイントと最新バージョンが提供され、一部のプロジェクトではGitHubリリース版が使用され、各バージョンにPHARがリリースされています.
複数のリポジトリの使用
これまで最も流行した技術の一つです.したがって,1つの
前の例を
すべてのものは実際には単一のリポジトリに保存でき、Symfonyのような他のパッケージの読み取り専用リポジトリしかありません.
この方法の主な利点は,Symfony,Laravel,PhpBBなどの最終リポジトリ割り当て器のような追加のツールを必要としない比較的簡単であることである.欠点は、1つではなく複数のパッケージを維持していることです.
構成の調整
もう1つの方法は、より高度なインストールとテストスクリプトを使用することです.前の例と比較して、私たちは他のことをすることができます.
私の経験では、それは有効ですが、これは肥大化したテストスクリプトを招き、実行中は比較的遅く、メンテナンスが難しく、新しい貢献者にもあまり友好的ではありません.
複数のcomposerを使用します.json
この方法は比較的新しい(PHPでは)ものであり,主に必要なツールが既製ではないため,このソリューションでさらに説明する.
この考え方は簡単です.例えば、下のほうです.
composer-bin-pluginは運に応じて生まれた.非常に簡単なComposerプラグインで、
このプラグインをインストールできます.
プラグインがインストールされ、
これにより、次のディレクトリ構造が作成されます.
そのうち
したがって、
さらに、異なるフレームワークでのライブラリの参照を例に挙げます.
したがって、Symfonyが参照している
Laravelが参照する
私たちの根
コアライブラリ間の参照関係をテストするには、それぞれ
本当にやってみると、この方法の主な欠点は冗長構成です.ルートプロファイル
この小さなパッケージプラグインcomposer-merge-pluginは、
今はこうです.
他の構成では、自動ロードおよび依存はルート
インストールに必要な依存関係を確認できます.
私はaliceのような多くのプロジェクトでこの方法を用い,PhpStanやPHP−CS−Fixerのような静的解析ツールやフレームブリッジとは異なる.もう1つの例はalice-data-fixturesであり、その中には多くの異なるORMブリッジ持続層(Doctrine ORM、Doctrine ODM、Eloquent ORMなど)とフレームワークの統合がある.
pharsに代わるもう一つのツールとして、私は複数のプライベートプロジェクトでそれを使用し、よく働いています.
結論
変な方法を見つけたり、お勧めしない人もいると信じています.ここでの目標は、特定のものを判断したり推薦したりすることではなく、いくつかの依存関係、および各依存関係の利点と欠点を管理するための可能な方法をリストすることです.だから、あなたの質問とあなたの個人的な好みによって、あなたに最適なものを選んでください.人々が言ったように、解決策はなく、バランスしかない.
PHPのアプリケーションまたはライブラリを作成する場合、通常は3つの依存関係があります.
これらの依存関係をどのように管理しますか?
ハード依存性:
{
"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を使用するときは、他にも覚えておく必要があります.
複数のリポジトリの使用
これまで最も流行した技術の一つです.したがって,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/phpstan
とphpmetrics/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 / acme
でcomposer 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に代わるもう一つのツールとして、私は複数のプライベートプロジェクトでそれを使用し、よく働いています.
結論
変な方法を見つけたり、お勧めしない人もいると信じています.ここでの目標は、特定のものを判断したり推薦したりすることではなく、いくつかの依存関係、および各依存関係の利点と欠点を管理するための可能な方法をリストすることです.だから、あなたの質問とあなたの個人的な好みによって、あなたに最適なものを選んでください.人々が言ったように、解決策はなく、バランスしかない.