25

PHP がメソッドのオーバーロード、継承、ポリモーフィズムなどの機能をサポートしているかどうかを調べようとしたところ、次のことがわかりました。

  • メソッドのオーバーロードをサポートしていません
  • 継承をサポートします

しかし、ポリモーフィズムについてはよくわかりません。私はこれをインターネットでグーグルで見つけました:

PHP では、ポリモーフィズムが本来あるべき形ではないことに注意してください。機能するということですが、データ型が弱いため、正しくありません。

では、それは本当にポリモーフィズムなのでしょうか?

編集 の隣に明確な YES または NO を配置することはできませんPHP supports polymorphism。「PHP はポリモーフィズムをサポートしていません」と述べるのは気が進まないでしょうが、実際にはそうです。またはその逆。

4

9 に答える 9

33
class Animal {
    var $name;
    function __construct($name) {
        $this->name = $name;
    }
}

class Dog extends Animal {
    function speak() {
        return "Woof, woof!";
    }
}

class Cat extends Animal {
    function speak() {
        return "Meow...";
    }
}

$animals = array(new Dog('Skip'), new Cat('Snowball'));

foreach($animals as $animal) {
    print $animal->name . " says: " . $animal->speak() . '<br>';
}

好きなようにラベルを付けることができますが、それはポリモーフィズムのように見えます。

于 2009-04-14T23:38:31.390 に答える
17

ただし、PHP は、他の言語 (Java など) で経験したようなメソッドのオーバーロードをサポートしていません。PHPでメソッドのオーバーロードを行うことはできますが、定義方法は異なります。特定のメソッドに異なる機能を持たせ、PHP で異なるパラメーター セットを使用する場合は、次のようにすることができます。

class myClass {
    public function overloadedMethod() {
        // func_num_args() is a build-in function that returns an Integer.
        // the number of parameters passed to the method.
        if ( func_num_args() > 1 ) {
            $param1 = func_get_arg(0);
            $param2 = func_get_arg(1);
            $this->_overloadedMethodImplementation2($param1,$param2)
        } else {
            $param1 = func_get_arg(0);
            $this->_overloadedMethodImplementation1($param1)
        }
    }

    protected function _overloadedMethodImplementation1($param1) {
        // code 1
    }

    protected function _overloadedMethodImplementation2($param1,$param2) {
        // code 2
    }
}

よりクリーンな実装が存在する可能性がありますが、これは単なるサンプルです。

PHP は継承とインターフェースをサポートしています。そのため、それらを使用してポリモーフィズムを実現できます。次のようなインターフェースを持つことができます:

// file: MyBackupInterface.php
interface MyBackupInterface {
    // saves the data on a reliable storage
    public function saveData();
    public function setData();
}

// file: myBackupAbstract.php
require_once 'MyBackupInterface.php';
class MyBackupAbstract implements MyBackupInterface {
     protected $_data;
     public function setData($data) {
         $this->_data= $data;
     }
     // there is no abstract modifier in PHP. so le'ts avoid this class to be used in other ways
     public function __construct() {
          throw new Exception('this class is abstract. you can not instantiate it');
     }
}

// file: BackupToDisk.php
require_once 'MyBackupAbstract.php';
class BackupToDisk extends MyBackupAbstract {
     protected $_savePath;

     // implement other methods ...

     public function saveData() {
           // file_put_contents() is a built-in function to save a string into a file.
           file_put_contents($this->_savePath, $this->_data);
     }
}

// file: BackupToWebService.php
require_once 'MyBackupAbstract.php';
class BackupToWebService extends MyBackupAbstract {
     protected $_webService;
     // implement other methods ...

     public function saveData() {
           // suppose sendData() is implemented in the class
           $this->sendData($this->_data);
     }
}

アプリケーションでは、次のように使用できます。

// file: saveMyData.php
// some code to populate $myData
$backupSolutions = array( new BackupToDisk('/tmp/backup') , new BackupToWebService('webserviceURL') );
foreach ( $backupSolutions as $bs ) {
    $bs->setData($myData);
    $bs->saveData();
}

そうです、PHP は強い型付けされた言語ではありません。$backupSolutions のいずれかが 'MyBackupAbstract' または 'MyBackupInterface' になることについて言及したことはありません。同じ方法。

于 2009-04-15T04:26:47.873 に答える
7

PHP にはクラスベースのポリモーフィズムがありますが、引数ベースのポリモーフィズムを実装するための正式なメカニズムがありません。

クラスベースのポリモーフィズムとは、基本クラスの観点から考え、呼び出されるメソッドを最終クラスに依存させることができることを意味します。たとえば、Triangle や Circle などのさまざまなクラスのオブジェクトの配列があり、これらの各クラスが同じクラス Shape を拡張している場合、配列を単なる形状のコレクションと見なすことができます。シェイプをループして、各シェイプの getArea() メソッドを呼び出すことができます。ポリモーフィズムとは、呼び出される getArea() メソッドがオブジェクトのクラスに依存する現象です。コードが円と三角形を区別せず、各オブジェクトを単なる形。同じコード行が別のコード ブロックを実行し、

引数ベースのポリモーフィズムは、一部の厳密に型指定された言語の機能であり、同じ名前の複数のメソッドを 1 つのクラスで定義できますが、それらのパラメーターが異なる場合に限ります。どのメソッドが呼び出されるかは、提供された引数によって異なります。メソッド内の引数の型を手動で検討することにより、PHP のような弱い型付けの言語で引数ベースのポリモーフィズムをエミュレートできます。これは、JavaScript にはネイティブの引数ベースのポリモーフィズムがないにもかかわらず、ポリモーフィック API を実装するために jQuery が行うことです。

したがって、「ポリモーフィズムをサポートする」とは、引数ベースのポリモーフィズムを実装するための正式なメカニズムを提供することを具体的に意味する場合、答えはノーです。より広い解釈では、答えはイエスです。クラスベースのポリモーフィズムの現象がすべてのオブジェクト指向言語で発生するのは当然のことです。また、暗黙的な型変換を実行して引数ベースのポリモーフィズムを実装する言語には意味がありません。

于 2013-12-27T17:49:30.447 に答える
6

__call()__callStatic()メソッドのオーバーロードをサポートする必要があります。詳細については、マニュアルを参照してください。または、正確には何を求めていますか?

更新:他の返信に気付きました。

メソッドをオーバーロードする別の方法については、次のことを考慮してください。

<?php
public function foo()
{
    $args = func_get_arg();
}

確かにきれいではありませんが、事実上、やりたいことは何でもできます。

于 2009-04-14T23:39:56.550 に答える
4

メソッドをオーバーライドすることはできますが、オーバーロードすることはできません。オーバーロード (C++ の場合) とは、複数のメソッドに同じメソッド名を使用し、パラメーターの数と型だけが異なる場合です。PHP は弱い型付けであるため、これは困難です。

オーバーライドは、サブクラスが基本クラスのメソッドを置き換える場所です。これは実際にはポリモーフィズムの基礎であり、PHP でそれを行うことができます。

于 2009-04-14T23:33:08.813 に答える
4

これをダックタイピングと呼ぶ人もいます。

于 2009-04-15T01:35:00.300 に答える
3

PHP では、他の言語でコンパイル エラーを生成するポリモーフィック コードを使用できます。これを簡単に説明します。予想されるコンパイル エラーを生成する最初の C++ コード:

class Base {};

class CommonDerivedBase {
   public:
    // The "= 0" makes the method and class abstract
    // virtual means polymorphic method
    virtual whoami() = 0;
};

class DerivedBase : public CommonDerivedBase {
   public:    
     void  whoami() { cout << "I am DerivedBase \n"; }
};

class Derived1 : public CommonDerivedBase {
  public:
    void  whoami() { cout << "I am Derived1\n"; }
};

class Derived2 : public CommonDerivedBase {
public:
 void whoami() { cout <<  "I am Derived2\n"; }
};

/* This will not compile */
void  test_error(Base& db)
{
   db.whoami();
}

C++ コンパイラは、次の行に対してこのエラー メッセージを発行します。db.whoami()

error: no member named 'whoami' in 'Base'

Base には whoami() というメソッドがないためです。ただし、類似の PHP コードは、実行時までそのようなエラーを検出しません。

class Base {}

abstract class DerivedCommonBase {
  abstract function whoami();
}

class Derived1 extends DerivedCommonBase {

 public function whoami() { echo "I am Derived1\n"; }
}

class Derived2 extends DerivedCommonBase {

 public function whoami() { echo "I am Derived2\n"; }
}

/* In PHP, test(Base $b) does not give a runtime error, as long as the object 
 * passed at run time derives from Base and implements whoami().
 */
function test(Base $b)
{
  $b->whoami(); 
}

$b = new Base();
$d1 = new Derived1();
$d2 = new Derived2();

$a = array();

$a[] = $d1;
$a[] = $d2;

foreach($a as $x) {

  echo  test($x);
}

test($d1);
test($d2);
test($b); //<-- A run time error will result.

foreach ループは出力で動作します

I am Derived1
I am Derived2

test($b) を呼び出して Base のインスタンスを渡すまで、実行時エラーは発生しません。したがって、foreachの後、出力は次のようになります

I am Derived1
I am Derived2
PHP Fatal error:  Call to undefined method Base::whoami() in
home/kurt/public_html/spl/observer/test.php on line 22

PHP をより安全にするためにできる唯一のことは、$b が意図したクラスのインスタンスであるかどうかをテストする実行時チェックを追加することです。

function test(Base $b)
{
  if ($b instanceof DerivedCommonBase) {
     $b->whoami(); 
  } 
}

しかし、ポリモーフィズムの要点は、そのような実行時チェックを排除することです。

于 2014-02-25T01:14:42.813 に答える