web-dev-qa-db-ja.com

PHPで関数を上書きすることは可能ですか?

宣言このような関数を...

function ihatefooexamples(){
  return "boo-foo!";
};

そしてredeclareこのようになります...

if ($_GET['foolevel'] == 10){
  function ihatefooexamples(){
    return "really boo-foo";
  };
};

その方法で関数を上書きすることは可能ですか?

とにかく?

61
Mark Lalor

編集

この回答が元の質問に直接対応していないというコメントに対処するため。 Google検索からここにアクセスした場合は、ここから始めてください

override_function と呼ばれる利用可能な関数があり、実際に法案に適合します。ただし、この関数が The Advanced PHP Debugger extensionの一部であることを考えると、override_function()が実稼働での使用を意図しているという議論をするのは困難ですしたがって、「いいえ」と言うと、元の質問者が念頭に置いた意図で関数を上書きすることはできません。

元の回答

ここで、OOP、特に多態性を利用する必要があります。

interface Fooable
{
    public function ihatefooexamples();
}

class Foo implements Fooable
{
    public function ihatefooexamples()
    {
        return "boo-foo!";
    }
}

class FooBar implements Fooable
{
    public function ihatefooexamples()
    {
        return "really boo-foo";
    }
}

$foo = new Foo();

if (10 == $_GET['foolevel']) {
    $foo = new FooBar();
}

echo $foo->ihatefooexamples();
93
Peter Bailey

ネームスペースphp> = 5.3のモンキーパッチ

インタープリターを変更するより回避性の低い方法は、モンキーパッチです。

モンキーパッチングは、実際の実装を独自の同様の「パッチ」に置き換える技術です。

忍者のスキル

PHP Ninjaのようにパッチを適用する前に、まずPHPの名前空間を理解する必要があります。

PHP 5.3以降では、一見Javaパッケージのようなものに相当する名前空間を紹介しましたが、まったく同じではありません。 PHPの名前空間は、特に関数と定数に対してフォーカスの階層を作成することにより、スコープをカプセル化する方法です。このトピックとして、 グローバル関数へのフォールバック は、説明を目的としています。

関数を呼び出すときに名前空間を提供しない場合、PHPは最初に現在の名前空間を検索し、次に階層を下に移動しますその接頭辞付き名前空間内で宣言された最初の関数を見つけて実行します。この例では、print_r();を_namespace My\Awesome\Namespace;_から呼び出している場合、PHPが行うことは、最初にMy\Awesome\Namespace\print_r();という関数を探し、次にMy\Awesome\print_r();次にMy\print_r();は、グローバル名前空間\print_r();でPHP組み込み関数を見つけるまで。

グローバル名前空間でfunction print_r($object) {}を定義することはできません。これは、その名前の関数が既に存在するため、名前の衝突が発生するためです。

次のようなものに致命的なエラーが発生することが予想されます。

_Fatal error: Cannot redeclare print_r()
_

ただし、名前空間の範囲内でそれを行うことを妨げるものは何もありません。

猿にパッチをあてる

いくつかのprint_r();呼び出しを使用するスクリプトがあるとします。

例:

_<?php
     print_r($some_object);
     // do some stuff
     print_r($another_object);
     // do some other stuff
     print_r($data_object);
     // do more stuff
     print_r($debug_object);
_

しかし、後で気が変わって、代わりに_<pre></pre>_タグでラップした出力が必要になります。あなたに起こったことはありますか?

print_r();へのすべての呼び出しを変更する前に、代わりにモンキーパッチを検討してください。

例:

_<?php
    namespace MyNamespace {
        function print_r($object) 
        {
            echo "<pre>", \print_r($object, true), "</pre>"; 
        }

        print_r($some_object);
        // do some stuff
        print_r($another_object);
        // do some other stuff
        print_r($data_object);
        // do more stuff
        print_r($debug_object);
    }
_

スクリプトは、グローバルMyNamespace\print_r();の代わりに\print_r();を使用するようになります

単体テストのモックに最適です。

nJoy!

60
nickl-

見て - override_function 関数をオーバーライドします。

override_function —組み込み関数をオーバーライドする

例:

override_function('test', '$a,$b', 'echo "DOING TEST"; return $a * $b;');
25
Sarfraz

簡単な答えはノーです。一度関数をPHP関数スコープで上書きすることはできません。

そのような匿名関数を使用するあなたのベスト

$ihatefooexamples = function()
{
  return "boo-foo!";
}

//...
unset($ihatefooexamples);
$ihatefooexamples = function()
{
   return "really boo-foo";
}

http://php.net/manual/en/functions.anonymous.php

13
RobertPitt

PHPで関数を再宣言することはできません。ただし、それらをオーバーライドできます。必要に応じてオーバーライドする関数を保存するには、 関数のオーバーライド関数の名前変更 をチェックしてください。

したがって、関数をオーバーライドすると、その関数は失われることに注意してください。あなたはそれを維持することを検討したいかもしれませんが、別の名前で。ただ言って。

また、これらがオーバーライドしたいクラスの関数である場合、サブクラスを作成し、rename_functionおよびoverride_functionを実行せずにクラスで関数を再宣言するだけで済みます。

例:

rename_function('mysql_connect', 'original_mysql_connect' );
override_function('mysql_connect', '$a,$b', 'echo "DOING MY FUNCTION INSTEAD"; return $a * $b;');
11
tomlikestorock

1つのケースのすべての関数をincludeファイルに含め、他の関数を別のincludeファイルに含めます。

たとえば、_simple.inc_にはfunction boofoo() { simple }が含まれ、_really.inc_にはfunction boofoo() { really }が含まれます

同じincに同じ種類のすべての機能を持たせることで、プログラムの読みやすさ/メンテナンスを支援します。

次に、メインモジュールの上部に

_  if ($_GET['foolevel'] == 10) {
    include "really.inc";
  }
  else {
    include "simple.inc";
  }
_
5
Ring Ø

PECL拡張機能を使用できます

しかし、それは私の意見では悪い習慣です。関数を使用していますが、 Decorator design pattern を確認してください。それから基本的なアイデアを借りることができます。

3
Gordon

いいえ、これは問題になります。 PHP変数関数

1
Chris

編集可能なインクルードファイルAがあり、インクルードファイルB(またはメインファイル)でその機能の一部をオーバーライドする関連ケースのソリューション:

メインファイル:

<?php
$Override=true; // An argument used in A.php
include ("A.php");
include ("B.php");
F1();
?>

ファイルAを含める:

<?php
if (!@$Override) {
   function F1 () {echo "This is F1() in A";}
}
?>

ファイルBを含める:

<?php
   function F1 () {echo "This is F1() in B";}
?>

メインファイルを参照すると、「これはBのF1()です」と表示されます。

1
David Spector

これが必要な状況に応じて、次のような匿名関数を使用できます。

$greet = function($name)
{
    echo('Hello ' . $name);
};

$greet('World');

...その後、いつでも新しい関数を指定された変数に設定できます

0
esud