6

これまでのところ、OOP プログラミングの概念と利点を理解できたと感じています。また、PHP でクラスを操作する方法を理解するのに苦労したことはありません。

しかし、これは私を少し混乱させました。たぶん理解できると思いますが、まだ確信が持てません。

私は一連のビデオ チュートリアルに従っています (外部リソースへのリンクに関するルールについてはわかりませんが、YouTube で見つけました)。苛立たしいことに、チューターがあるクラスを別のクラス内のパラメーターとして渡すことにした場合を除きます。少なくとも私はそれが起こっていると思います。

Class Game
{

    public function __construct()
    {
        echo 'Game Started.<br />';
    }
    public function createPlayer($name)
    {
        $this->player= New Player($this, $name);
    }
}


Class Player
{

    private $_name;

    public function __construct(Game $g, $name)
    {
        $this->_name = $name;
        echo "Player {$this->_name} was created.<br />";
    }
}

次に、Game クラスのオブジェクトをインスタンス化し、そのメソッドを呼び出しています。

$game = new Game();
$game-> createPlayer('new player');

かなり苛立たしいことに、家庭教師はなぜこれを行ったのかを実際には説明しておらず、私が見る限り、それを正当化するコード内の呼び出しを表示していません。

Player のマジック メソッド コンストラクタは、Game クラスを参照として渡していますか? これは、参照によって Player クラス内でクラス全体にアクセスできるということですか? 特定のメソッドやプロパティを指さずに $this を参照する場合、クラス全体を参照していますか?

これが起こっているのなら、なぜ私はそれをしたいのでしょうか? ゲーム クラス内にプレーヤーを作成した場合、ゲーム クラス内のプレーヤー プロパティとメソッドにアクセスできますよね? Player クラス内にも Game クラスが必要なのはなぜですか? たとえば、Player クラス内で createPlayer() を呼び出すことはできますか?

私の説明が紛らわしかったら申し訳ありません。

私の質問は次のようになります。パラメータとして正確に渡すのは何ですか?なぜ毎日のOOPプログラミングでそれをやりたいのですか?

4

3 に答える 3

4

これはタイプヒントと呼ばれ、クラス全体をパラメーターとして渡すのではなく、最初のパラメーターのタイプについてクラスプレーヤーにヒントを与えるラッターです。

PHP 5では、型ヒントが導入されています。関数は、パラメーターをオブジェクト(関数プロトタイプでクラスの名前を指定することにより)、インターフェース、配列(PHP 5.1以降)、または呼び出し可能(PHP 5.4以降)にすることができるようになりました。ただし、デフォルトのパラメータ値としてNULLが使用されている場合は、それ以降の呼び出しの引数として許可されます。

(phpマニュアルから抜粋)

これは、参照によってクラス全体がPlayerクラス内でアクセス可能であることを意味しますか?

クラス全体ではありませんが、パラメータとして渡すクラスのインスタンスにアクセスできます

于 2012-10-29T01:01:23.810 に答える
3

このメソッドは、他のオブジェクトのインスタンスであるオブジェクトを取得することを想定しており、Gameエラーが発生します。

Gameちょうどここのインスタンスを渡しています:New Player($this, $name); キーワード$thisは、現在のオブジェクト インスタンスを参照します。

そして最後に....私(そしてそのことについては他の誰も)は、作者がGameインスタンスを渡した後はインスタンスを使用していないため、なぜそれを行ったのかわかりません。

クラスのインスタンスを渡すのはなぜですか?
ユーザーを入力として受け入れ、何らかのロジックに従ってユーザーに対して何かを行うクラスを想像してみてください。(関数名とクラス名は一目瞭然であるため、コードにコメントはありません)

class User{
  protected $name,$emp_type,$emp_id;
  protected $department;

  public function __construct($name,$emp_type,$emp_id){
     $this->name = $name;
     $this->emp_type = $emp_type;
     $this->emp_id = $emp_id;
  }

  public function getEmpType(){
     return $this->emp_type;
  }

  public function setDep($dep){
    $this->department = $dep;
  }
}


class UserHub{

  public function putUserInRightDepartment(User $MyUser){
      switch($MyUser->getEmpType()){
           case('tech'):
                $MyUser->setDep('tech control');
                break;
           case('recept'):
                $MyUser->setDep('clercks');
                break;
           default:
                $MyUser->setDep('waiting HR');
                break;
      }
  }
}

$many_users = array(
    0=>new User('bobo','tech',2847),    
    1=>new User('baba','recept',4443), many more
}

$Hub = new UserHub;
foreach($many_users as $AUser){
   $Hub->putUserInRightDepartment($AUser);
}
于 2012-10-29T01:55:18.273 に答える
2
/**
* Game class.
*/
class Game implements Countable {
    /**
    * Collect players here.
    * 
    * @var array
    */
    private $players = array();

    /**
    * Signal Game start.
    * 
    */
    public function __construct(){
        echo 'Game Started.<br />';
    }

    /**
    * Allow count($this) to work on the Game object.
    * 
    * @return integer
    */
    public function Count(){
        return count($this->players);
    }

    /**
    * Create a player named $name.
    * $name must be a non-empty trimmed string.
    * 
    * @param string $name
    * @return Player
    */
    public function CreatePlayer($name){
        // Validate here too, to prevent creation if $name is not valid
        if(!is_string($name) or !strlen($name = trim($name))){
            trigger_error('$name must be a non-empty trimmed string.', E_USER_WARNING);
            return false;
        }
        // Number $name is also not valid
        if(is_numeric($name)){
            trigger_error('$name must not be a number.', E_USER_WARNING);
            return false;
        }
        // Check if player already exists by $name (and return it, why create a new one?)
        if(isset($this->players[$name])){
            trigger_error("Player named '{$Name}' already exists.", E_USER_NOTICE);
            return $this->players[$name];
        }
        // Try to create... this should not except but it's educational
        try {
            return $this->players[$name] = new Player($this, $name);
        } catch(Exception $Exception){
            // Signal exception
            trigger_error($Exception->getMessage(), E_USER_WARNING);
        }
        // Return explicit null here to show things went awry
        return null;
    }

    /**
    * List Players in this game.
    * 
    * @return array
    */
    public function GetPlayers(){
        return $this->players;
    }

    /**
    * List Players in this game.
    * 
    * @return array
    */
    public function GetPlayerNames(){
        return array_keys($this->players);
    }
} // class Game;


/**
* Player class.
*/
class Player{
    /**
    * Stores the Player's name.
    * 
    * @var string
    */
    private $name = null;

    /**
    * Stores the related Game object.
    * This allows players to point to Games.
    * And Games can point to Players using the Game->players array().
    * 
    * @var Game
    */
    private $game = null;

    /**
    * Instantiate a Player assigned to a Game bearing a $name.
    * $game argument is type-hinted and PHP makes sure, at compile time, that you provide a proper object.
    * This is compile time argument validation, compared to run-time validations I do in the code.
    * 
    * @param Game $game
    * @param string $name
    * @return Player
    */
    public function __construct(Game $game, $name){
        // Prevent object creation in case $name is not a string or is empty
        if(!is_string($name) or !strlen($name = trim($name))){
            throw new InvalidArgumentException('$name must be a non-empty trimmed string.');
        }
        // Prevent object creation in case $name is a number
        if(is_numeric($name)){
            throw new InvalidArgumentException('$name must not be a number.');
        }
        // Attach internal variables that store the name and Game
        $this->name = $name;
        $this->game = $game;
        // Signal success
        echo "Player '{$this->name}' was created.<br />";
    }

    /**
    * Allow strval($this) to return the Player name.
    * 
    * @return string
    */
    public function __toString(){
        return $this->name;
    }

    /**
    * Reference back to Game.
    * 
    * @return Game
    */
    public function GetGame(){
        return $this->game;
    }

    /**
    * Allow easy access to private variable $name.
    * 
    * @return string
    */
    public function GetName(){
        return $this->name;
    }
} // class Player;

// Testing (follow main comment to understand this)
$game = new Game();
$player1 = $game->CreatePlayer('player 1');
$player2 = $game->CreatePlayer('player 2');
var_dump(count($game)); // number of players
var_dump($game->GetPlayerNames()); // names of players

コードをより適切な方法で書き直し、不足している変数をいくつか追加して、そのコードを無意味にしました。

  • プレーヤー クラスでは、ゲームを保存しません。
  • ゲーム クラスでは、1 人のプレーヤーのみをサポートします。
  • エラーチェックはありません...どこにもありません。

これらすべてに加えて修正:

  • 例外を追加しました(オブジェクトの作成を防ぐため)
  • Try{} catch(...){}OOP開発者が知っておくべき例外処理
  • count($game) プレイヤーを許可する Countable インターフェイスを実装
  • 読みやすくするためのその他のトリック

コメントに従ってください。コードを読んだ後、コードがより意味のあるものになることを願っています。

于 2012-10-29T01:39:25.483 に答える