PHP DBから抽出データ、配列、SESSION、class
解決済
回答 4
投稿
- 評価
- クリップ 0
- VIEW 2,947
はじめに
たぶん、何やってんだろう?という質問内容かと思いますが、アドバイスをいただければと思います。
やりたいこと
漠然としてはいますが、たぶんclassを作るのに、すごい遠回りをし始めているんだと思います。
そして、MVCなどの考え的なのはなんとなくわかるのですが、イマイチclassとかの部分がまだ理解できておりません。
とりあえず、例えばですが、、、
<select>
<option></option>
<?php
$dbh = connectDb();
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$sql = "SELECT id, name FROM users ORDER BY id ASC";
$stmt = prepare($sql);
$stmt->execute();
while ($row = $stmt->fetch()) :
$id = $row['id'];
$name = $row['name'];
?>
<option value="<?= $id; ?>"><?= $name; ?></option>
<?php endwhile; ?>
</select>
上記のように、SelectのoptionをDBから引っ張ってきて作成するというものがあるとします。
これだけで、普通にできているのですが、あえて、、、処理をわけてわざわざ複雑な感じにしてみたいと思います。
※なんでするの?というのは、とりあえず聞かないでください、、、、
とりあえず考えてみたこと
classとかの部分が勉強不足なので、とりあえず処理を分けるということだけを考えてみました。
[index.php]
<!-- select_box -->
<?php select_box(); ?>
[db.php]
function select_db() {
$dbh = connectDb();
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$sql = "SELECT id, name FROM users ORDER BY id ASC";
$stmt = prepare($sql);
$stmt->execute();
$rows = $stmt->fetchAll();
$_SESSION['rows'] = $rows;
}
[processing.php]
function select_box() {
select_db();
$cnt = count($_SESSION['rows']);
echo "<select name='select_box'><option></option>";
for ($i = 0; $i <= $cnt; $i++) {
$select['id'] = $_SESSION['rows'][$i]['staff_id'];
$select['name'] = $_SESSION['rows'][$i]['name'];
echo "<option value=" . $select['id'] . ">" . $select['name'] . "</option>";
}
echo "</select>";
とりあえずの結果
表示することはとりあえずできました。
問題等
処理を分けるという考え方だけなら、indexは表示だけ、dbがDBからのデータを抽出しただけ、processingでデータを加工?したという感じ?になったような気はしますが、、、
とりあえず、よくわかってない部分で、、、
1.これでデータを取得したら、なぜかデータの最後に空白ができてた。
当然最初に<option></option>があるので、最初は空白ですが、その後データの最後にまた空白ができてしまっていました。
2.上記はとりあえず独学と、いろいろ質問させてもらったりサイトを見たのを使いながらゴリゴリ書いていきましたが、これをもう少しこうすれば?というアドバイスやヒントなどいただければと思って質問いたしました。
ここは、こうしたほうがわかりやすい。
ここは、無駄でなくてもいいはず。
さらにここは省略するべきなど、、、ご意見いただけますでしょうか?
なんじゃこの書き方は?と思われるでしょうが、参考のために、、、
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+1
2.上記はとりあえず独学と、いろいろ質問させてもらったりサイトを見たのを使いながらゴリゴリ書いていきましたが、これをもう少しこうすれば?というアドバイスやヒントなどいただければと思って質問いたしました。
基本的な文法や使い方がわかってきている段階に見えますので、
ここいらで書籍を使って学習することをお勧めします。
もちろんネットで学習できることも多いですし、書籍でもダメなものはありますが、
「なぜ処理をまとめた方が便利なのか」という部分の学習も含めてコードが設計されていることが多いので、
効率よく学習出来ることが多いです。
例えば今回のケースだと
戻り値の使い道についてピンと来ていないように見えます。
[db.php]
function select_db() {
$dbh = connectDb();
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$sql = "SELECT id, name FROM users ORDER BY id ASC";
$stmt = prepare($sql);
$stmt->execute();
$rows = $stmt->fetchAll();
$_SESSION['rows'] = $rows;
}
だと切り出しただけであんまり意味が無いです。
具体的には、結果を$_SESSIONに格納してしまっているので、
どこか別のタイミングで呼ばれたとしても$_SESSIONを意図せず汚してしまうことになります。
なので例えば
function select_db() {
$dbh = connectDb();
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$sql = "SELECT id, name FROM users ORDER BY id ASC";
$stmt = prepare($sql);
$stmt->execute();
$rows = $stmt->fetchAll();
return $rows;
}
と、結果を戻り値で返すようにしてやって
[processing.php]
function select_box() {
$rows = select_db();
$cnt = count($rows);
echo "<select name='select_box'><option></option>";
for ($i = 0; $i <= $cnt; $i++) {
$select['id'] = $rows[$i]['staff_id'];
$select['name'] = $rows[$i]['name'];
echo "<option value=" . $select['id'] . ">" . $select['name'] . "</option>";
}
echo "</select>";
としてやれば、select_db()は別の場所で使っても問題の無い関数になります(処理の再利用が出来るようになったので、別ページで同じことをしようとした時に同じコードをコピペしなくてよくなります)
同様に、
引数についても正しく使えば便利で
例えば
function select_db($order,$sort) {
$dbh = connectDb();
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$sql = "SELECT id, name FROM users ORDER BY :order :sort";
$stmt = $dbh->prepare($sql);
$stmt->bindValue(':order', $order, PDO::PARAM_STR);
$stmt->bindValue(':sort', $sort, PDO::PARAM_STR);
$stmt->execute();
$rows = $stmt->fetchAll();
return $rows;
}
とすれば、呼び出すタイミングでソートするキーと昇順/降順を指定するだけで、実際に実行されるSQLを変更することが出来て便利だったりします。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
MVCは自信ないのでoptionの件だけ・・・
最後のoptionが空になるのはfor ($i = 0; $i <= $cnt; $i++)
のせいですね
count($_SESSION['rows'])
でデータ数を取得していますが実際のデータは0から始まるので
for ($i = 0; $i < $cnt; $i++)
としてあげてください。
$data
配列のデータ数が2
の場合は$data[0]
と$data[1]
の2つだけと考えて見てください。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
とりあえず自分の好みでいうとこんな感じかなあ
[index.php]
<!-- select_box -->
<select name='select_box'><option></option>
<?php echo select_box(); ?>
</select>
[db.php]
function select_db($sql) {
$dbh = connectDb();
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$stmt = prepare($sql);
$stmt->execute();
return $stmt->fetchAll();
}
[processing.php]
function select_box() {
$sql = "SELECT id, name FROM users ORDER BY id ASC";
$ret = '';
foreach (select_db($sql) as $row) {
$id = $row['id'];
$name = $row['name'];
$ret .= "<option value=" . $id . ">" . $name . "</option>\n";
}
return $ret;
}
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
基本的にDBのクラスからはHTMLを出力したりするのはメンテしにくくなるので、単純に配列出会ったり、オブジェクトを返すだけにしたほうが汎用性が上がります。
スケルトンで書いてみましたが、以下のようにクラスを実装してみては?
<?php
class MySQL
{
/**
* ホスト
*/
private $host = 'localhost';
/**
* データベース
*/
private $database = 'database';
/**
* ユーザー
*/
private $user = 'root';
/**
* パスワード
*/
private $pass = '';
/**
* DSN
*/
private $dsn = null;
/**
* 接続
*/
private $dbh = null;
/**
* コンストラクタ
*/
public function __construct()
{
$this->connect();
}
/**
* 接続する
* @return $dbh
*/
private function connect()
{
$this->dsn = "mysql:dbname={$this->database};host={$this->host};charset=utf8";
$this->dbh = new PDO($this->dsn, $this->user, $this->pass);
}
/**
* SELECT
* @param string $sql
* @param array $arrParams
* @return array
*/
public function select($sql, $arrParams)
{
// @todo
return $arrRecords;
}
/**
* UPDATE
* @param string $sql
* @param array $arrParams
* @return bool
*/
public function update($sql, $arrParams)
{
// @todo
return $bool;
}
/**
* INSERT
* @param string $sql
* @param array $arrParams
* @return int
*/
public function insert($sql, $arrParams)
{
// @todo
return $insertId;
}
}
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.19%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2016/05/20 08:41
確かにreturnの返り値や引数という部分がぴんと来ていませんでした。。。
SESSIONもこんなにやるとUNSETも増えたりで、なんか大変だよな、、、とは思っていたのですが、、、そこに気づけませんでした。
大変参考になりました!ありがとうございます!