- PR -

PHP5のオブジェクト指向

1
投稿者投稿内容
abe
常連さん
会議室デビュー日: 2003/08/14
投稿数: 31
投稿日時: 2006-01-13 06:55
PHP5でオブジェクト指向が強化されたとの事で勉強しておりますが、
次のように、オブジェクトの配列をプロパティとして持たせることは可能でしょうか?

<?php
class Player {
    public function __construct($name) {
        $this->_name = $name;
    }
    private $_name;
    public function get_name() {
        return $this->_name;
    }
}

class Team {
    public function __construct($name) {
        $this->_name = $name;
    }
    private $_name;
    public $_aryPlayer;
    private $_coach;
    public function add($player) {
        $_aryPlayer[] = $player;
    }
    public function set_coach($coach) {
        $this->_coach = $coach;
    }

    public function get_coach() {
        return $this->_coach;
    }

    public function get_aryPlayer() {
        return $this->_aryPlayer;
    }
}

$team = new Team(1,Giants);
$player1 = new Player(Oh);
$player2 = new Player(Nagashima);

$team->add($player1);
$team->add($player2);
$team->set_coach($player2);

//これはうまくいきます。
echo $team->get_coach()->get_name();

//次がうまくいきません。
echo $team->get_aryPlayer()[0]->get_name();
?>

どのようにしたらうまく実装出来るでしょうか?

ちょっと違う質問なのですが
オブジェクトをプロパティとして持つ事が出来るため、
次のような事が起きた場合どうなるのでしょうか?

クラスPlayerのプロパティとしてTeamを持たせます。
クラスTeamのプロパティとしてPlayerを持たせます。

それぞれのプロパティはgetメソッドで呼び出せるとして
再帰的にオブジェクトが続いてしまわないでしょうか?
そのような事は防がれているのでしょうか?

PHP5のオブジェクト指向について良い書籍、WEBサイトがありましたら、
是非教えてください。
流れプログラマ
常連さん
会議室デビュー日: 2005/09/30
投稿数: 26
投稿日時: 2006-01-13 12:43
コード:
<?php
class Player {
        public function __construct($name) {
                $this->_name = $name;
        }
        private $_name;
        public function get_name() {
                return $this->_name;
        }
}

class Team {
        public function __construct($name) {
                $this->_name = $name;
                $this->_aryPlayer = array(); // 追加
        }
        private $_name;
        public $_aryPlayer;
        private $_coach;
        public function add($player) {
                $this->_aryPlayer[] = $player; // 修正
        }
        public function set_coach($coach) {
                $this->_coach = $coach;
        }

        public function get_coach() {
                return $this->_coach;
        }

        public function &get_aryPlayer() {
                return $this->_aryPlayer;
        }
}

$team = new Team(1,Giants);
$player1 = new Player(Oh);
$player2 = new Player(Nagashima);

$team->add($player1);
$team->add($player2);
$team->set_coach($player2);

//これはうまくいきます。
echo $team->get_coach()->get_name();

//次がうまくいきません。
//echo $team->get_aryPlayer()[0]->get_name();
$players = $team->get_aryPlayer();
echo $players[0]->get_name();
?>


問題なく動作させるには、こんな感じです。無理して1行に書かなくてもいいんじゃないかと・・・
abe
常連さん
会議室デビュー日: 2003/08/14
投稿数: 31
投稿日時: 2006-01-13 13:56
流れプログラマさん、どうもありがとうございます。
そもそものコードはご指摘どおり
クラスTeamのaddメソッドに問題がありました。
頂いたヒントを元に下記のようにしてチームの選手名一覧を取得出来ました。


コード:
$players = $team->get_aryPlayer();
foreach($member as $player) {
	echo $player->get_name();
}
//OhNagashima

流れプログラマ
常連さん
会議室デビュー日: 2005/09/30
投稿数: 26
投稿日時: 2006-01-13 17:31
引用:

クラスPlayerのプロパティとしてTeamを持たせます。
クラスTeamのプロパティとしてPlayerを持たせます。

それぞれのプロパティはgetメソッドで呼び出せるとして
再帰的にオブジェクトが続いてしまわないでしょうか?


質問の意味が今ひとつはっきりしませんが、双方向に参照しあっていること自体では問題にならないと思います。もっとも、下のような処理を望んでいる場合には、無限ループになりますけど。
コード:
class Player {
    private $_Team;
    public function get_Team() {
        return $self->_Team->get_Player();
    }
}

class Team {
    private $_Player;
    public function get_Player() {
        return $self->_Player->get_Team();
    }
}



問題が発生するかどうかは、どちらかと言えば設計により変わります。Player と Team の関係についても、少なくとも2通りの可能性があります。
 ・1人のPlayerが、1つのTeamに所属する
 ・1人のPlayerが、複数のTeamに所属する

通常、1つのTeamには複数のPlayerが所属するものですから、上は「N対1」の関係、下は「N対N」の関係になります。
abe
常連さん
会議室デビュー日: 2003/08/14
投稿数: 31
投稿日時: 2006-01-13 19:43
流れプログラマさん、どうもありがとう御座います。
1対Nの関係です。

具体的には次のような件で今回の疑問が生じました。
データベースからプレイヤーのリストを作成するようなアプリケーションを考えています。
データベースの構造は下記のようになっていて、プレイヤー名と所属チーム名の一覧表示させます。
以下の二つのコードを考えました。
コード:
テーブル1 team

| team_id | team_name |
------------------------
| 1       | Giants    |
| 2       | Tigers    |
------------------------
テーブル2 player

| player_name | team_id |
--------------------------
| Oh          | 1       |
| Nagashima   | 1       |
--------------------------

class Team {
	$_name;
	$_aryPlayers = array();
	public function set_name($name) {
		$this->_name = $name;
	}
}

class Player {
	$_name;
	$_Team;
	
	static getPlayers($db) {
		$stt = $db->prepare("SELECT * FROM player INNER JOIN team ON player.team_id = team.team_id");
		$rs = $db->execute($stt);
		$aryPlayer = array();
		while($row = $rs->fetchRow("DB_FETCHMODE_ASSOC")) {
			$objPlayer = new Player();
			$objPlayer->set_name($row['player_name']);
			$objPlayer->get_Team()->set_name($row['team_name']);
		}
		return $aryPlayer;
	}
}

$db = DB::connect("mysql://id:pass@localhost/baseball");
$players = Player::getPlayers($db);
foreach($players as $player) {
	echo $player->get_name();
	echo " in "
	echo $player->get_Team()->get_name();
	echo "\\\\n";
}

//Oh in Giants
//Nagashima in Giants



しかし、次のように実現する事も可能だと思います。
コード:
class Team {
	$_name;
	$_aryPlayers = array();

	public static function getTeamFromId($db,$team_id) {
		$stt = $db->prepare("SELECT * FROM team WHERE team_id=?");
		$rs = $db->execute($stt,array($team_id));
		$objTeam = new Team();
		while($row = $rs->fetchRow("DB_FETCHMODE_ASSOC") {
			$objTeam->set_name($row['team_name']);
		}
		return $objTeam;
	}
}

class Player {
	$_name;
	$_team_id;
	
	static getPlayers($db) {
		$stt = $db->prepare("SELECT * FROM player");
		$rs = $db->execute($stt);
		$aryPlayer = array();
		while($row = $rs->fetchRow("DB_FETCHMODE_ASSOC")) {
			$objPlayer = new Player();
			$objPlayer->set_team_id($row['team_id']);
			$objPlayer->set_name($row['player_name']);
		}
		return $aryPlayer;
	}
}

$db = DB::connect("mysql://id:pass@localhost/baseball");
$players = Player::getPlayers($db);
foreach($players as $player) {
	echo $player->get_name();
	$team_id = $player->get_team_id();
	$team_name = Team::getTeam($db,$team_id)->get_name();
	echo " in ";
	echo $team_name;
}
//Oh in Giants
//Nagashima in Giants



1番目の方法の場合、PlayerのオブジェクトとしてTeamを持たせて
DBへのSELECT回数が1回で済んでいます。その代わり双方向からクラスを参照する為に、
無限ループの可能性もあり、プログラミング作法として良いのかどうか分かりません。

2番目の方法の場合、PlayerのオブジェクトにはTeamを持たせずに、
Teamのスタティックメソッドでteam_idからteam_nameを得ています。
こちらの場合、playerテーブルに存在するPlayerの数だけ余計にSELECTしてしまいます。

もちろん1番目の方法でPlayerのプロパティとしてTeamを持たせずに、
単なるStringの$team_id,$team_nameというプロパティを持たせれば良いのかもしれませんが
チームのテーブルが他のフィールドも所持している場合はチーム名だけでなく、チームの他の情報も
得たいかもしれません。その場合に単なるStringのプロパティを沢山持たせる事は
オブジェクト指向の精神に反する気もします。

2番目の方法では、Teamを双方向から参照させずに回避していますが、
たった一回のプレイヤーリストを出すためにSELECTを何度も実行しないといけません。
アプリケーションに接続するユーザーが増えた場合は負荷の問題が発生する気が
します。

また、拡張してリーグのクラスを作って、
リーグにチームリストを持たせたいと考えています。
リーグ[]->チームリスト[]->プレイヤーリスト[] のように階層的な構造にしたいと
考えています。そしてプレイヤーリストの一覧でリーグ名やリーグのその他の情報も
表示させるように拡張したいと考えています。

長くなってしまいましたが上述のようなジレンマに悩んでいます。
オブジェクト指向やWEBアプリケーションのセオリーが分からず、
どうするのが行儀が良く綺麗で効率が良いのか分かりません。

皆さんはこういう場合にどういった方法を取るのが良いとお考えですか?
是非皆さんのご意見を聞かせて下さい。
1

スキルアップ/キャリアアップ(JOB@IT)