6

コードライブラリをスタンドアロンのPHPクラスとしてリリースするとします。次に、誰かがそのライブラリのバージョン1.0をアプリケーションで使用します。後で、ライブラリのバージョン2.0をリリースしました。同じ人が、何らかの理由で、新しいリリースとの下位互換性を壊したため、アプリケーションで1.0と2.0の両方を並べて使用する必要があります。

クラス名が異なる場合は、名前の競合がないため、両方を含めてインスタンス化するのは簡単です。しかし、クラス名が同じに保たれていると、問題が発生します。

include /lib/api-1.0/library.php;
$oldlibary = new Library();

include /lib/api-2.0/library.php;
$newlibrary = new Library();

両方の名前の2つのクラスをロードできないため、これは機能しませんLibrary。別の開発者が提案した代替案の1つは、名前空間を使用することでした。以下が機能するはずです。

namespace old {
    include /lib/api-1.0/library.php;
}
namespace new {
    include /lib/api-2.0/library.php;
}

$oldlibary = new old\Library();
$newlibrary = new new\Library();

残念ながら、これはあまりスケーラブルではありません。これは2インスタンスの状況で機能しますが(できれば、そもそも使用する必要はありません)、3、4、5、またはそれ以上のインスタンスにスケーリングするには、追加の名前空間を定義する必要がありますそもそもこれらの名前空間を使用していない場合は、不要なコードがたくさんあります。

では、名前空間を動的に作成し、ファイルを含め、そのファイルに含まれるクラスを一意の名前の変数でインスタンス化する方法はありますか?


もう少し説明を追加しましょう...

いくつかのCMSプラットフォーム用のプラグイン/モジュールを構築する他の開発者が使用するライブラリのセットを構築しています。理想的には、誰もが常に最新バージョンのライブラリを使用することを保証できませんが、新しいバージョンが利用可能になったときにエンドユーザーが常にモジュールをアップグレードすることを保証することはできません。

私が使用しようとしているユースケースは、エンドユーザーが2人の異なる開発者によって2つの異なるモジュールをインストールする場合です。それらをAppleOrangeと呼びます。どちらのモジュールも私のライブラリのバージョン1.0を使用しています。これは素晴らしいことです。一度インスタンス化することができ、両方のコードセットが機能の恩恵を受けることができます。

後で、このライブラリにマイナーパッチをリリースします。1.xブランチとの下位互換性を壊さないため、バージョン1.1です。Appleの開発者はすぐにローカルバージョンを更新し、システムの新しいエディションをプッシュします。Orangeの開発者は休暇中で、気にしません。

エンドユーザーがAppleを更新すると、彼女は私のライブラリの最新のメンテナンスリリースを入手します。これはメンテナンスリリースであるため、バージョン1.0を完全に置き換えるのが安全であると想定されています。そのため、コードは1.1をインスタンス化するだけであり、開発者がリリースを更新することを気にしない場合でも、 Orangeはメンテナンスパッチの恩恵を受けます。

後で、何らかの理由でFacebookにフックを追加するようにAPIを更新することにしました。新しい機能とAPI拡張機能はライブラリに関して大きく変更されるため、バージョンを2.0に上げて、すべての状況で下位互換性がない可能性があることを示すフラグを立てます。もう一度、Appleは入って、彼のコードを更新します。何も壊れませんでした。彼は自分のフォルダにある私のライブラリを/lib最新バージョンに置き換えただけです。 オレンジは、ピエロになるために学校に戻ることを決心し、モジュールの保守を停止したため、更新は行われません。

エンドユーザーが新しいリリースでAppleを更新すると、彼女は自動的に私のライブラリのバージョン2.0を取得します。しかし、オレンジは彼のシステムにすでにFacebookフックを追加するコードを持っていたので、2.0がデフォルトで彼のライブラリにロールインされた場合、競合が発生します。そのため、完全に置き換えるのではなく、 Apple用に2.0を一度インスタンス化し、 Orangeに付属の1.0バージョンを並べてインスタンス化して、適切なコードを使用できるようにします。

このプロジェクトの全体的なポイントは、サードパーティの開発者が信頼できるものに依存することなく、私のコードに基づいてシステムを構築し、必要なときにコードを更新できるようにすることです。エンドユーザーにとって何も壊れてはなりません。他の誰かのシステム内で使用するときにライブラリを更新することは、すべてのクラス参照を調べて変更するのではなく、単純なファイル置換である必要があります。

4

3 に答える 3

3

少し別のルートを決めました。名前空間メソッドは機能しますが、クラスのバージョンごとに異なる名前空間が必要です。したがって、使用可能な名前空間の数を事前に定義する必要があるため、実際にはスケーラブルではありません。

代わりに、クラスの特定の命名スキーマとバージョンローダー/インスタンス化を決定しました。

各クラスは次の形式を取ります。

<?php
if( ! class_exists( 'My_Library' ) ) { class My_Library { } }

if( ! class_exists( 'My_Library_1_0' ) ) :
class My_Library_1_0 extends My_Library {
    ... class stuff ...
}
endif;

My_Libraryクラスには、実際にはライブラリに固有のいくつかの識別子(目的、互換性ステートメントなど)が含まれることになります。こうすることで、他の論理チェックを実行して、先に進み、実際にライブラリのバージョン1.0であると主張する前に権利 が存在することを確認できます。が欲しいです。My_LibraryMy_Library_1_0

次に、メインプロジェクトで使用するローダークラスがあります。

<?php
class Loader {
    static function load( $file, $class, $version ) {
        include( $file );
        $versionparts = explode('.', $version);
        foreach($versionparts as $part) $class .= '_' . $part;
        return new $class();
    }
}

これが完了すると、Loader静的メソッドを使用する場合は、クラスのインスタンスまたは単純な参照の両方をロードするために使用できます。

$reference = Loader::load( 'library.php', 'My_Library', '1.0' );

$loader = new Loader();
$instance = $loader->load( 'library.php', 'My_Library', '1.0' );

私が狙っていた名前空間のバージョンとはまったく同じではありませんが、それは機能し、エンドユーザーのために物事を壊すという私の懸念を軽減します。ただし、の2つの異なるバージョンは同じであると想定してMy_Library_1_0います...したがって、サードパーティの開発者が何をしているのかを知っていることに依存しています。

于 2011-04-27T03:37:20.597 に答える
1

では、名前空間を動的に作成し、ファイルを含め、そのファイルに含まれるクラスを一意の名前の変数でインスタンス化する方法はありますか?

はい、そのような方法は存在します。evalハンドラーとstreamハンドラーを使用して、好きなことを行うことができます。しかし、それは悪い習慣であり、間違ったアプローチです-ファクトリメソッドを使用してみることができます(コードはテストされていません-例を示しているだけです):

<?php

if (!class_exists('Library')) {

    class Library
    {
        public static function create($version)
        {
            if (class_exists($c = 'Library' . $version))
                return new $c();
            return null;
        }
    }

}

class Library1
{

}

class Library2
{

}

...
于 2011-04-26T15:41:29.747 に答える
-1

ユーザーにバージョンを選択させ、それに応じてAPIファイルをロードします

ファイル名は動的に決定可能である必要があります。次に例を示します。

include('/lib/api-'.$versionId.'/library.php'); 

バージョン-1.0の場合は賢明です

ユーザー入力が単一の小数に変換され、float悪意のないものがないことを確認するように注意してください。

于 2011-04-26T15:46:42.613 に答える