• ベストアンサー
  • 困ってます

クラスの中で関数・変数を使う方法

  • 質問No.8351885
  • 閲覧数243
  • ありがとう数4
  • 気になる数0
  • 回答数10
  • コメント数0

お礼率 48% (25/52)

クラスの中で関数や変数を使う方法はどのようにやるのでしょうか?

public function getInvitedUsers($inviter_id) {
$stmt = $this->pdo->prepare(implode(' ', array(
'SELECT *',
'FROM `user`',
'WHERE `sno` = ?',
)));
$stmt->bindValue(1, $inviter_id, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll();
}


この
'WHERE `sno` = ?',

部分の?のとこにセッションで保存した固有の番号と比較したいのですがどこに記述するべきかわからず困っております。

try {

// 表示したいユーザーの情報を取得
$user = DB::connect()->getUser($_SESSION['user_id']);

ここでユーザー情報を取得して

$invit = $user['no']

固有の番号を入れて

'WHERE `sno` = $invit',

このようなイメージで比較したいのですが、$invit = $user['no']の部分はどこに記述するべきなのでしょうか?
そもそもこのような'WHERE `sno` = $invit',での記述はできるのでしょうか?

無知で申し訳ございませんが、どうぞよろしくお願いいたします。

質問者が選んだベストアンサー

  • 回答No.10
  • ベストアンサー

ベストアンサー率 77% (407/525)

>> $recursion_level
>> この数値をいじるといけてしまうのでしょうか?

そうですね。

3再帰以内の人を取得したいならば
$this->getInvitationLeaves($_SESSION['user_id'], 3)

3再帰ちょうどの人を取得したいならば
$this->getInvitationLeaves($_SESSION['user_id'], 3, true)

といった感じでいくらでも調節できますね。getInvitationTreeメソッドは他にもいろいろ応用が利きそうなので、そのときは是非使いまわしましょう。

出来た時の喜びを掴みたいという意思があれば、自然にどんどんスキルアップしていけますよ!私も最初はド素人から始まって汚いコードばかり書いていましたが、オブジェクト指向でTwitterアプリを手さぐりで作ってみたりしているうちに自然にスキルが身についてきて、そこからQ&Aサイトでの回答をするようになった今の自分があります。
お礼コメント
milkkokoa94856

お礼率 48% (25/52)

ありがとうございました!!

簡単なことは色々できるのですが、応用となると今回みたいにお手上げになっております(´;ω;`)

私も早く回答側に回って困ってる人を助けれる日を夢見て頑張ります(笑)

やはり色々実際にやって数をこなしていきたいと思っておりますので今後も意味不明なご質問をさせていただくかもしれませんが、もし目に付いたら救ってやってください(>人<;)

丁寧な回答ありがとうございました^^
投稿日時:2013/11/21 22:39

その他の回答 (全9件)

  • 回答No.9

ベストアンサー率 77% (407/525)

今気づいたのですが、NULLとFALSEによる区別を行うならば、変数$doneは用意する必要が無くなりますね。というわけで

public function getInvitationTree($root_id, $recursion_level = 0) {
____$tree = array($root_id => null);
____$info = array($root_id => $this->getUser($root_id));
____$stmt = $this->pdo->prepare(implode(' ', array(
________'SELECT *',
________'FROM `user`',
________'WHERE `sno` = ?',
____)));
____for ($i = 0; $i <= $recursion_level, $i++) {
________array_walk_recursive($tree, function (&$v, $k) use ($stmt, &$info) {
____________if ($v === false) {
________________return;
____________}
____________$stmt->bindValue(1, $k, PDO::PARAM_INT);
____________$stmt->execute();
____________if (!$stmt->rowCount()) {
________________$v = false;
________________return;
____________}
____________$v = array();
____________foreach ($stmt as $row) {
________________$v[$row['id']] = null;
________________$info[$row['id']] = $row;
____________}
________});
____}
____return array(
________'tree' => $tree,
________'info' => $info,
____);
}

で十分でしょう。
補足コメント
milkkokoa94856

お礼率 48% (25/52)

か、完璧ですΣ(゜д゜lll)
やってみたいことが綺麗にできました!!

毎回お手数をお掛けして本当に申し訳ないです。
とりあえずせっかく教えていただいたこのオブジェクト指向でできたもので色々試しているのですが、出来た時の喜びがすごいです(笑)

つまずいたときは苦労がすごいですけど、というか今回のような難易度の高いことをしてみるとまだまだつまずいて毎回助けていただいている現状に涙目です。

じっくりコードを見直して色々試してみます。
ちなみにこれは以前
(再帰レベル1指定なので3,4の招待ユーザーは取得しません)
とおっしゃっていたのですが、どんどん奥に(2階層の人が紹介した3階層の人)いこうと思うと
$recursion_level
この数値をいじるといけてしまうのでしょうか?

そうなってくるとコードは変わるのでしょうか?
せっかくなのでどんどん奥に行ったりしてこの辺の理解を深めようと思います><
投稿日時:2013/11/21 19:23
  • 回答No.8

ベストアンサー率 77% (407/525)

【私が期待している構造の例】で紹介した例で、ユーザー (3,4) と ユーザー(5) の集合を区別する必要ってありますか?再帰を最後まで行った結果見つかったグループと、途中でそれ以上再帰を行う対象が見つからずに中断したグループのことです。もしこれを区別する必要があるなら

if (!$stmt->rowCount()) {
____$done[$k] = true;
____return;
}



if (!$stmt->rowCount()) {
____$done[$k] = true;
____$v = false;
____return;
}

として、NULLとFALSEで区別でもしてみましょうか。この変更を加えた上で、葉要素のユーザー情報だけを取得するgetInvitationTreeメソッドのラッパーメソッドも作ってみましょう。

$root_id
→根となるID。

$recursion_level
→再帰を行う回数を表す0以上の整数。デフォルトは0。

$only_deepest
→ True: 先ほど述べた「NULL」のみに限定する
→ False(デフォルト): 先ほど述べた「NULL」「FALSE」の両方を取得する

public function getInvitationLeaves($root_id, $recursion_level = 0, $only_deepest = false) {
____$data = $this->getInvitationTree($root_id, $recursion_level);
____$leaves = iterator_to_array(new RecursiveIteratorIterator(new RecursiveArrayIterator($data['tree'])));
____if ($only_deepest) {
________$leaves = array_filter($leaves, 'is_null');
____}
____$ret = array();
____foreach ($leaves as $id => $dummy) {
________$ret[] = $data['info'][$id];
____}
____return $ret;
}

メソッドを呼んでみた結果をvar_dumpかprint_rで確認してみてください。
  • 回答No.7

ベストアンサー率 77% (407/525)

※ $_SESSION['user_id'] は 1 としています。
補足コメント
milkkokoa94856

お礼率 48% (25/52)

本当に毎回お世話になり申し訳ないです。
完璧です、自分の表示したい通りのことを理解し導いて頂きました。

print_r($ret['info']);
で中身をみると下記の通り表示されました。

1000 山田1号でログイン中

Array
(
____[1000] => Array
________(
____________[id] => 1000
____________[name] => 山田1号
________)

_____[1001] => Array
________(
____________[id] => 1001
____________[name] => 山田2号
____________[invitid] => 1000
____________[invit] => 山田1号
________)

_____[1002] => Array
________(
____________[id] => 1002
____________[name] => 山田3号
____________[invitid] => 1001
____________[invit] => 山田2号
________)

_____[1003] => Array
________(
____________[id] => 1003
____________[name] => 山田4号
____________[invitid] => 1001
____________[invit] => 山田2号
________)

_____[1004] => Array
________(
____________[id] => 1004
____________[name] => 山田5号
____________[invitid] => 1001
____________[invit] => 山田2号
________)

_____[1005] => Array
________(
____________[id] => 1005
____________[name] => 山田5号
____________[invitid] => 1001
____________[invit] => 山田2号
________)

)

と確認でき、

print_r($ret['tree']);
をした場合

Array
(
______[1000] => Array
________(
____________[1001] => Array
________________(
____________________[1002] =>
____________________[1003] =>
____________________[1004] =>
____________________[1005] =>
________________)
____________)
)

となり表示したい2階層部分の1002~1005が取得できています。

実際にページに表示しようと多次元配列の記事を読み
<?=h($ret[])?>
この[]の中に指定をしようと色々やってみたのですが、通常のサイトでは自分で決めた数値でやる場合は載っているのですが、今回のように取得した数値の場合などの記事が見つけれず数時間悩みましたがアドバイスを受けたく追記してしまいました。

この辺の応用力もなく自分に凹みましたがもうしわけございませんが1002~1005の部分の[invit]の文字列を取得したい場合[]には何を指定するべきなのでしょうか。
投稿日時:2013/11/21 11:32
お礼コメント
milkkokoa94856

お礼率 48% (25/52)

お礼の部分に失礼いたします。

先ほどやっと
$second = $ret['info'];

<?php foreach ($second as $snouser): ?>
<div class="check">会員ID:<?php echo "<pre>"; var_dump($snouser['name']); echo "</pre>";?></div>
<?php endforeach; ?>

このようにして名前のみを取得できました。

山田1号
山田2号
山田3号
山田4号
山田5号

なのですが2階層目なので山田3号~5号までを表示したいのですが、どうもうまくいきません。

クラスの方で制御するのか表示先のforeachで制御できるのか失礼ながらこちらにご質問させていただきましたm(_ _)m
投稿日時:2013/11/21 16:32
  • 回答No.6

ベストアンサー率 77% (407/525)

getInvitationTreeの返り値をvar_dumpなりprint_rなりしてみてください。

【私が期待している構造の例】

$ret = DB::connect()->getInvitationTree($_SESSION['user_id'], 1);

としたとき、1が2,5を招待し、2が3,4を招待していたと仮定すると、
(再帰レベル1指定なので3,4の招待ユーザーは取得しません)

$ret['tree'] = array(
____1 => array(
________2 => array(
____________3 => null,
____________4 => null,
________),
________5 => array(
____________null,
________),
____),
);
$ret['info'] = array(
____1 => 1の情報の配列,
____2 => 2の情報の配列,
____3 => 3の情報の配列,
____4 => 4の情報の配列,
____5 => 5の情報の配列,
);

となるように書いたのですが、合ってますかね・・・?
デバッグしていないので期待と違っていればごめんなさい。

array_walk_recursive
http://php.net/manual/ja/function.array-walk-recursive.php

この関数は末端の要素だけを順番に取り出そうとします。この性質を利用して、$recursion_level の指定をうまく反映させています。$done にセットしているのは「招待ユーザーが見つからなかったユーザー」で、これはそれらを次のループで取り出す対象から外すために行っています。

なお、$stmt を use せずにクロージャの中で $this->getInvitedUsers($k) を呼んでもよかったのですが、PDOで同じプリペアドステートメントを複数回利用する場合、一度用意した PDOStatement オブジェクトを使いまわしたほうが圧倒的にパフォーマンスが向上するため、このように少々回りくどい方法を採りました。

以下も参考にどうぞ↓

array_walk
http://www.php.net/manual/ja/function.array-walk.php

無名関数(クロージャ)
http://php.net/manual/ja/functions.anonymous.php
  • 回答No.5

ベストアンサー率 77% (407/525)

$recursion_level,

$recursion_level;

なかなか気づきませんでした;;
補足コメント
milkkokoa94856

お礼率 48% (25/52)

お手数をおかけして申し訳ありませんでした。

DB.phpの方は無事エラーはなくなったのですが、HTML部分で
Warning: htmlspecialchars() expects parameter 1 to be string, array given in

調べると配列ではなく文字列を入れろということらしいのですが、

$invited = DB::connect()->getInvitedUsers($_SESSION['user_id']);

これでセッションからの紹介の部分に関しては呼び出せております。

$second = DB::connect()->getInvitationTree($_SESSION['user_id']);

これでいま作成している2段目を接続しているのですが、HTMLで表示させようとすると先ほどのエラーがでてしまいます。

HTML部分での記述はどのようにするのでしょうか。
毎回お世話になって質問しづらいのですが、初めて見るエラーばかりでアドバイス通り翻訳してみたもののわかりませんでした。orz
投稿日時:2013/11/20 07:47
  • 回答No.4

ベストアンサー率 77% (407/525)

大幅に訂正

public function getInvitationTree($root_id, $recursion_level = 0) {
____$tree = array($root_id => null);
____$info = array($root_id => $this->getUser($root_id));
____$stmt = $this->pdo->prepare(implode(' ', array(
________'SELECT *',
________'FROM `user`',
________'WHERE `sno` = ?',
____)));
____for ($i = 0; $i <= $recursion_level, $i++) {
________array_walk_recursive($tree, function (&$v, $k) use ($stmt, &$info, &$done) {
____________if (isset($done[$k])) {
________________return;
____________}
____________$stmt->bindValue(1, $k, PDO::PARAM_INT);
____________$stmt->execute();
____________if (!$stmt->rowCount()) {
________________$done[$k] = true;
________________return;
____________}
____________$v = array();
____________foreach ($stmt as $row) {
________________$v[$row['id']] = null;
________________$info[$row['id']] = $row;
____________}
________});
____}
____return array(
________'tree' => $tree,
________'info' => $info,
____);
}
補足コメント
milkkokoa94856

お礼率 48% (25/52)

すごい丁寧にありがとうございます。

自分がやってみようと思ったことがこんなに複雑だったとは一人では何日悩んでもここにたどり着いてない気がしてゾッとします。

今やってみたら
Parse error: syntax error, unexpected ')', expecting ';' in
のエラーで
その行には
for ($i = 0; $i <= $recursion_level, $i++) {
の記述です。

エラーのとおり)に注目してみたものの私のレベルではよくわかりませんでした。

)の数もあってたと思うのですがその周辺も全て数えたのですが間違いないようでした。

その場合は、ほかのとこがエラーになっているのでしょうか?
投稿日時:2013/11/19 20:29
  • 回答No.3

ベストアンサー率 77% (407/525)

えーっと、つまり

「まず自分が招待した人々を求める」
「次にそれら1人1人が招待した人々を求める」

(根を0段目とすると)ツリー構造の2段目まで求めたい、こういうことでしょうか?そうであればテーブル・カラムを新たに作成する意味って無いんじゃないですかね。

getInvitedUsersメソッドはそのまま残しておいて、新たにgetInvitationTreeメソッドを作成します。


【getInvitationTreeメソッド】
招待関係をIDでツリー上につなげた配列(tree)と、各IDに対応する情報を格納した配列(info)を配列でまとめて返す。

$root_id
→根となるID。

$recursion_level
→再帰を行う回数を表す0以上の整数。デフォルトは0。

public function getInvitationTree($root_id, $recursion_level = 0) {
____$tree = array($root_id => null);
____$info = array($root_id => $this->getUser($root_id));
____$stmt = $this->pdo->prepare(implode(' ', array(
________'SELECT *',
________'FROM `user`',
________'WHERE `sno` = ?',
____)));
____for ($i = 0; $i <= $recursion_level, $i++) {
________array_walk_recursive($tree, function (&$v, $k) use ($stmt, &$info) {
____________$stmt->bindValue(1, $k, PDO::PARAM_INT);
____________$result = $stmt->execute();
____________$v = array($result['id'] => null);
____________$info[$result['id']] = $result;
________});
____}
____return array(
________'tree' => $tree,
________'info' => $info,
____);
}

デバッグしてないので多分ミスあると思います、ご容赦を。
  • 回答No.2

ベストアンサー率 77% (407/525)

getInvitedUsersメソッドの役割は「引数で渡されたIDのユーザーが招待したユーザーを取得する」でいいですよね?であればすでに回答にあるように引数として渡すだけでいいと思います。

snoカラムってInt型でしたよね?それならばPDO::PARAM_INTで合ってますね。

それと以前の補足に対して回答するのを忘れていましたが、申し訳ないですがよく意味が分かりませんでした。MySQLのエラーメッセージって結構親切なので高卒レベル程度の英語が読めれば何となくどこを直せばいいかぐらいは分かるんじゃないでしょうか。
補足コメント
milkkokoa94856

お礼率 48% (25/52)

とんでもございません、説明が下手で申し訳ないですm(_ _)m
なんとか回答を頂いたセッションで表示することができました。

今回の質問はもう一段階招待した人を表示したいと思っております。
なので、

<?php foreach ($user as $suser): ?>
<li><?=h($suser['id'])?></li>
<?php endforeach; ?>

表示は
1001
1002
1003


これで今回のセッションを使って招待した人を3人表示できたとします。

例のIDと名前は下記のとおり
1001 山田
1002 佐藤
1003 花子

さらにこの3人のIDから招待した人を表示したいと思っております。

DB.phpへ

public function getSecondInvited($inviter_id) {
$stmt = $this->pdo->prepare(implode(' ', array(
'SELECT *',
'FROM `syoukai`',
'WHERE `syoba` = ?',
)));
$stmt->bindValue(1, $inviter_id, PDO::PARAM_INT);
$stmt->execute();
return $stmt->fetchAll();
}

として『?』の部分に1001と山田の番号を入れるとうまく表示できています。

なので『?』の部分に取得した$suser['id']を当てはめたいのですが代入したりして『?』の部分に変えてみたり色々やってみたもののうまくいきません。

WHEREには関数や変数を使うことができないのでしょうか?
このような場合はどのように記述するべきなのでしょうか?

説明がごちゃごちゃしていて申し訳ございませんがヒントでもアドバイスを頂けると幸いです。
投稿日時:2013/11/19 12:52
  • 回答No.1

ベストアンサー率 36% (784/2137)

$stmt->bindValue(1, $inviter_id, PDO::PARAM_INT);
としているのだから、getInvitedUsers()の引数に
$_SESSION['user_id']を渡せばいいのでは。

あと、バインドしている変数がint型を指定しているので、
PDO::PARAM_INTではなくPDO::PARAM_STRに変えてあげれば
いいんじゃないでしょうか。

http://php.net/manual/ja/pdostatement.bindvalue.php
http://www.php.net/manual/ja/pdo.constants.php


もしでしたら、プリペアドステートメント、プレースホルダーについて
改めて学習し直すといいかもしれません。
お礼コメント
milkkokoa94856

お礼率 48% (25/52)

ありがとうございました、セッションの方を渡して無事に表示することができました^^
投稿日時:2013/11/19 12:41
結果を報告する
このQ&Aにはまだコメントがありません。
あなたの思ったこと、知っていることをここにコメントしてみましょう。
AIエージェント「あい」

こんにちは。AIエージェントの「あい」です。
あなたの悩みに、OKWAVE 3,600万件のQ&Aを分析して最適な回答をご提案します。

関連するQ&A

ピックアップ

ページ先頭へ