12

次のフォームを使用して PHP で新しいクラス インスタンスを宣言することのパフォーマンス、セキュリティ、または「その他」の意味は何ですか?

<?php
  $class_name = 'SomeClassName';
  $object = new $class_name;
?>

これは不自然な例ですが、大きな if/switch ステートメントを避けるために、ファクトリ (OOP) でこの形式が使用されているのを見てきました。

すぐに思いつく問題は、

  1. 引数をコンストラクターに渡す機能が失われます(LIES。Thanks Jeremy)
  2. eval() のような匂いがして、テーブルにもたらされるすべてのセキュリティ上の懸念があります (ただし、必ずしもパフォーマンスに関する懸念があるとは限りませんか?)

他にどのような影響がありますか、または「Rank PHP Hackery」以外にこれを調査するために使用できる検索エンジン用語は何ですか?

4

10 に答える 10

8

コンストラクターに引数を渡すことができるようです。これが私のテストコードです。

<?php

class Test {
    function __construct($x) {
        echo $x;
    }
}

$class = 'Test';
$object = new $class('test'); // echoes "test"

?>

それがあなたの言いたいことですよね?

ですから、あなたが言及し、私が考えることができる他の唯一の問題は、そのセキュリティですが、それを安全にするのはそれほど難しいことではなく、eval()を使用するよりも明らかにはるかに安全です。

于 2008-09-07T02:01:32.037 に答える
8

実行時の解決に関する問題の 1 つは、オペコード キャッシュ (APC など) の処理が非常に困難になることです。それでも、今のところ、インスタンス化するときにある程度の間接化が必要な場合は、質問で説明したようなことをするのが有効な方法です。

みたいなことをしない限り

$classname = 'SomeClassName';
for ($x = 0; $x < 100000; $x++){
  $object = new $classname;
}

あなたはおそらく元気です:-)

(私のポイントは、ここでクラスを動的に検索してから害を及ぼすことはありません。頻繁に行うと、そうなるでしょう)。

また、 $classname を外部から設定できないようにしてください。インスタンス化する正確なクラスをある程度制御したいでしょう。

于 2008-09-07T20:10:44.163 に答える
5

次を使用して、動的な数のパラメーターでインスタンス化することもできます。

<?php

$class = "Test";
$args = array('a', 'b');
$ref = new ReflectionClass($class);
$instance = $ref->newInstanceArgs($args);

?>

しかしもちろん、これを行うことでさらにオーバーヘッドが追加されます。

セキュリティの問題については、あまり重要ではないと思います。少なくとも、eval() と比較すると何もありません。最悪の場合、間違ったクラスがインスタンス化されます。もちろん、これは潜在的なセキュリティ違反ですが、悪用するのははるかに難しく、クラス名を定義するためにユーザー入力が本当に必要な場合は、許可されたクラスの配列を使用して簡単にフィルター処理できます。

于 2008-09-15T12:26:37.537 に答える
4

クラス定義を検索する前に変数の名前を解決しなければならないため、実際にパフォーマンスが低下する可能性があります。しかし、クラスを動的に宣言しないと、「動的」または「メタ」プログラミングを行う実際の方法はありません。コード生成プログラムや、ドメイン固有の言語構造のようなものを作成することはできません。

内部フレームワークのいくつかのコア クラスのいたるところでこの規則を使用して、コントローラー マッピングへの URL を機能させます。また、多くの商用オープン ソース アプリケーションでも見てきました (例を掘り下げて投稿します)。とにかく、私の答えの要点は、より柔軟で動的なコードを作成する場合、おそらくパフォーマンスがわずかに低下するだけの価値があるように思われるということです。

ただし、言及しなければならないもう 1 つのトレードオフは、パフォーマンスは別として、変数名に十分注意しない限り、コードが少しわかりづらく、読みにくくなるということです。ほとんどのコードは一度書かれ、何度も読み直されて変更されるため、読みやすさは重要です。

于 2008-09-07T02:55:38.223 に答える
2

アラン、動的なクラスの初期化に問題はありません。この手法はJava言語にも存在し、Class.forClass('classname')メソッドを使用して文字列をクラスに変換できます。if-条件のリストを持つ代わりに、アルゴリズムの複雑さをいくつかのクラスに任せることも非常に便利です。動的クラス名は、コードを変更せずに拡張用に開いたままにしておく場合に特に適しています。

私自身、データベース テーブルと組み合わせてさまざまなクラスをよく使用します。1 つの列に、レコードの処理に使用されるクラス名を保持します。これにより、新しいタイプのレコードを追加し、既存のコードを 1 バイトも変更することなく独自の方法で処理できるという大きな力が得られます。

パフォーマンスを気にする必要はありません。オーバーヘッドはほとんどなく、オブジェクト自体は PHP で超高速です。何千もの同一のオブジェクトを生成する必要がある場合は、Flyweightデザイン パターンを使用してメモリ フットプリントを削減します。特に、サーバーで数ミリ秒節約するためだけに、開発者としての時間を犠牲にするべきではありません。また、オペコード オプティマイザは、この手法とシームレスに連携します。Zend Optimizer でコンパイルされたスクリプトは誤動作しませんでした。

于 2008-09-08T12:39:21.620 に答える
1

だから私は最近これに遭遇し、動的インスタンス化を使用することの「その他の」影響について考えを述べたいと思いました。

1 つのことfunc_get_args()は、物事に少しレンチを投げます。たとえば、特定のクラス (ファクトリ メソッドなど) のコンストラクタとして機能するメソッドを作成したいとします。ファクトリ メソッドに渡されたパラメーターを、インスタンス化するクラスのコンストラクターに渡すことができる必要があります。

もしあなたがそうするなら:

public function myFactoryMethod() 
{
  $class = 'SomeClass'; // e.g. you'd get this from a switch statement
  $obj = new $class( func_get_args() );
  return $obj;
}

そして、次のように呼び出します。

$factory->myFactoryMethod('foo','bar');

実際には、最初/唯一のパラメーターとして配列を渡しています。これは、new SomeClass( array( 'foo', 'bar' ) ) これは明らかに私たちが望んでいるものではありません。

解決策(@Seldaekが指摘したように)では、配列をコンストラクターのパラメーターに変換する必要があります。

public function myFactoryMethod() 
{
  $class = 'SomeClass'; // e.g. you'd get this from a switch statement
  $ref = new ReflectionClass( $class );
  $obj = $ref->newInstanceArgs( func_get_args() );
  return $obj;
}

注: このcall_user_func_arrayアプローチを使用して新しいオブジェクトをインスタンス化することはできないため、これは を使用して達成できませんでした。

チッ!

于 2013-01-07T20:14:01.800 に答える
0

カスタム フレームワークで動的インスタンス化を使用しています。私のアプリケーション コントローラは、リクエストに基づいてサブコントローラをインスタンス化する必要があります。これらのコントローラのロードを管理するために巨大で絶え間なく変化する switch ステートメントを使用するのは、まったくばかげています。その結果、アプリ コントローラーを変更して呼び出すことなく、コントローラーをアプリケーションに次々と追加できます。URI がフレームワークの規則に従っている限り、アプリ コントローラーは実行時まで何も知らなくてもそれらを使用できます。

私は現在、このフレームワークを実動ショッピング カート アプリケーションで使用していますが、パフォーマンスも非常に良好です。そうは言っても、私はアプリ全体で 1 つまたは 2 つの場所でのみ動的クラス選択を使用しています。どのような状況で頻繁に使用する必要があるのか​​ 、そしてそれらの状況が、アプリケーションを過度に抽象化したいというプログラマーの欲求に苦しんでいるものなのかどうか疑問に思います(私は以前にこれについて罪を犯しました).

于 2008-09-07T20:17:52.260 に答える
0

1 つの問題は、たとえば、そのような静的メンバーに対処できないことです。

<?php
$className = 'ClassName';

$className::someStaticMethod(); //doesn't work
?>
于 2008-09-15T12:31:45.683 に答える
0
class Test {
    function testExt() {
    print 'hello from testExt :P';
    }
    function test2Ext()
    {
    print 'hi from test2Ext :)';
    }
}


$class = 'Test';
$method_1 = "testExt";
$method_2 = "test2Ext";
$object = new $class(); // echoes "test"
$object->{$method_2}(); // will print 'hi from test2Ext :)'
$object->{$method_1}(); // will print 'hello from testExt :P';

このトリックは php4 と php5 の両方で機能します:D お楽しみください..

于 2009-01-20T14:40:19.483 に答える
0

call_user_func(array($className, 'someStaticMethod')@coldFlame: パラメータをcall_user_func_array()渡すために使用できる IIRC

于 2008-09-15T14:32:35.360 に答える