色々なサイトを拝見させて頂き勉強をしていると
phpからmysqlで接続し呼び出すときに
prepare(array(SELECT * FROM request WHERE id = ?,));
このような一文で呼び出すものと行数を分け
prepare(implode(' ', array(
'SELECT *',
'FROM `request`',
'WHERE `id` = ?',
このように書いているものとあります。
個人的には行数を分けていた方がわかりやすいので後者のほうで書いているのですが、これは作る人の気分でかき分けていいものなのか気になり質問させて頂きました。
また後者ではどういうタイミングで区切るのかわからないというのもあります。
SELECT * FROM users INNER JOIN category ON users.category = category.id INNER JOIN images ON users.category = images.id
このように3つのテーブルを内部統合したくこの文を作りmysql上で叩くと3つ統合され表示されます。
しかし上記の文に当てはめphpから叩くとエラーがでます。
素直に1行で書けばよいのですが、分からないからというってスルーするのはあまり良くないかと重いご質問させて頂きました。
この3つのテーブルの場合、後者の書き方ではどのタイミングで区切るのでしょうか。
No.1
- 回答日時:
配列に入れるのがいいかどうかは意見がわかれるところですね
句ごとに生成して処理ができるので効率的な場合もありますが
複雑なJOINをするときには結合関係が分かりづらくなる場合もあります。
SQLの原則としてSQL文中の改行は無視されるという特徴があります
(もちろんSELECTをSEL(改行)ECT のようにするのはNG)
なので、プログラムに埋め込む際にも
$sql="select a,b,c
from hoge
where a=100
";
のようにユーザーが見やすいように改行をいれて書いたり
$sql="select a,b,c ";
$sql.="from hoge ";
$sql.="where a=100 ";
のような処理をしてもよいでしょう。
(implodeする場合とちがい各文字列の後ろにスペースを入れておかないと
SQL文の句がつまってしまいエラーになります)
もちろん
select a,b,cの個所を
select a
,b
,c
などに分解することもできるので、場合によっては効率的なプログラムが書けます
それとせっかく覚え始めなので「SELECT *」はよほどのことがない限り
つかわない癖をつけたほうがいいです。
もちろん雑な挙動確認をする場合は便利な機能ですが、必要な項目だけ
表示するのがSQLの原則です。
往々にして同じ名称のカラムが発生することからもプログラムでつかうと
データアクセスが一意でなくなり想定と違う挙動となる場合があります
この回答への補足
ご回答ありがとうございました。
やはり用途によって使い分けということですね、わかりやすい書き方を心がけ両方つかえたほうがいいですね。
一点追加でご質問なのですが「`id`」のように「`」で括ってあるのですがこれは何のためなのでしょうか?「`」でくくらない場合でも出力に問題なかったので、どういう時に括るべきなのでしょうか?
'や”のように文字列のときはこれ、のような感じで決まりごとがあるのでしょうか?
No.2
- 回答日時:
当時の私のコーディング癖が移っちゃったかな(罪悪感
・implodeで配列を繋ぐ
→ 文字列リテラルにインデント用のスペースが大量に紛れ込むのが何となく気持ち悪いので今でも使ってます。
・バッククオート(`)での囲い込み
→ 最近は予約語にしか使ってません。予約語をある程度覚えているのであればこっちのほうが見やすいし、と感じてきたので。
・DB::connect() という書き方
→ シングルトンとしてあのサンプルは当初書いていました。しかし、シングルトンで作るとさまざまなデメリットがあることがわかってきたので、今は素直に new DB() と書いていますね。この場合もちろん __construct() は public にしないといけません。
Wikipedia - シングルトンパターン
http://ja.wikipedia.org/wiki/Singleton_%E3%83%91 …
この回答への補足
To_aru_User 様
以前は色々ご指導ありがとうございました。
最近やっと仕事が落ち着いてきたので釣り仲間のサイトを作りながら再度勉強をし直しています(笑)
DB::connect() という書き方についてデメリットというのはセキュリティなどについてということでしょうか?それとも手間が多くかかるなどのデメリットでしょうか?
現在は
getUsersのSELECT文など接続をファイルにまとめて、必要なページで
try {
$user=DB::connect()->getUsers($_SESSION['id']);
$user=DB::connect()->getImages($_SESSION['id']);
}
このような感じで呼び出しています。
この方法ではダメということでしょうか?
No.3
- 回答日時:
シングルトンパターンはインスタンスを外部からアクセス出来ないところに持ち、2回目以降では新しくインスタンスを作らずに同じものを返すことになります。
だから$user = DB::connect()->getUsers($_SESSION['id']);
$user = DB::connect()->getImages($_SESSION['id']);
と書いても、(コンストラクタがpublicならば)
$db = new DB();
$user = $db->getUsers($_SESSION['id']);
$user = $db->getImages($_SESSION['id']);
と書いても同じ動作をしていたのです。
データベースとコネクションを1個張ればいいだけのような単純な開発であればこれでもそれほど問題はないのですが、大規模な開発では必ずしもそうとは限りません。そして…一番の理由が、ソフトウェア開発における「テスト」という工程で、シングルトンクラスは「非常にテストしにくい」扱いになってしまうのです。
一応「どこからでも同じインスタンスを参照できる」ことや「1行で流れるように記述できる」ことは便利ではあるのですが、諸刃の剣ですね。最近では避けられることの方が多いようです。
https://www.google.co.jp/search?q=%E3%82%B7%E3%8 …
この回答への補足
なるほどです、使い安いがデメリットが多いということなのですね。
今現在
class DB {
/**
* 静的プロパティ
*/
private static $instance;
/**
* 動的プロパティ
*/
private $pdo;
/**
* このクラス自身のインスタンスを生成して返す。
* 2回目以降は1回目に生成したものを返すようにして、
* 「シングルトン(singleton)」を実現している。
*
* @static
* @access public
* @return DB
*/
public static function connect()
{
if (!self::$instance) {
self::$instance = new self;
}
return self::$instance;
}
/**
* PDOを使って実際にデータベースに接続する。
* コンストラクタだがクラス内部のconnectメソッドからしか呼ばれないため、
* アクセス権限はprivateに設定。
*
* @access private
*/
private function __construct() {
$this->pdo = new PDO(
// DSN (Data Source Name)
sprintf('mysql:dbname=%s;host=%s;charset=utf8',
DB_NAME,
DB_HOST
),
DB_USER,
DB_PASS,
array(
// SQL実行失敗時にPDOExceptionをスローさせる
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
// デフォルトフェッチを連想配列形式に指定
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
// PDOStatement::rowCount()をSELECTに対しても使えるように設定
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true,
)
);
}
このような感じにしてクラスの中を書いている状態です。
これを直すには
private function __construct()
のプライベートをパブリックになおして
$db = new DB();
$user = $db->getUsers($_SESSION['id']);
このような感じに直せばよいのでしょうか?
クラス内のものは今のとこすべてパブリックになっているので、それで修正できると思っているのですがあっているでしょうか?
No.4
- 回答日時:
はい、そんな感じでいいと思います。
但し、・必要最小限のメソッドだけを public にする
・継承クラスを作るときに流用したいものは protected にする
・それ以外は全て private にする
・プロパティは原則的に全て private で、必要に応じてゲッターやセッターを用意することを考える( http://qiita.com/mpyw/items/1cb6fc8170b6a8c8eb04 )
という方針は維持したほうがいいですね。いわゆる「カプセル化」ってやつです。
【その他連絡】
外部からの変数の受け取りに関して、filter_input関数がものすごく有用であることが分かったので、以下の記事を更新しました。
http://qiita.com/mpyw/items/2f9955db1c02eeef43ea
プリペアドステートメントのエミュレーションはしないほうがいいという結論を得たので、以下の記事を更新しました。
http://qiita.com/mpyw/items/b00b72c5c95aac573b71
この回答への補足
To_aru_User様
ありがとうございます。
なんか覚えることが色々あってわけがわからなくなりそうですが、サイトの方参考に頑張っていこうと思います。
小島よしおにはコーヒー吹き出しそうで危なかったです(笑)
住まいが田舎なもので中々詳しい人に習うことができないので、アドバイスを頂けるこの環境が非常に助かります。
聞いてばかりではダメだとはわかるのですが、調べると記事が古かったりmysql関数を使っているものだったり探す時間ばかり取られて、しかもこれで綺麗にかけているのかも不安になったりと結局こちらのベテランの方の声に頼らざるをえません(笑)
書籍でPHPの本を色々見て回るのですがPDOについてやクラス・カプセル化のようなコチラでアドバイス頂けるものについてのことを書いてあるものが見当たりません(田舎で在庫がないだけなのかもしれませんが)。
pdo・クラス・カプセル化について説明してあるTo_aru_User様のオススメの書籍などあれば教えていただけませんでしょうか。
家ではTo_aru_User様のサイトを見させて頂いてるのですが、仕事先で携帯を長時間いじるのはあまり良くないので本でオススメがあれば最後にアドバイス頂ければ幸いです。
No.5ベストアンサー
- 回答日時:
【パーフェクトPHP】
PHP5.3のときに書かれたものでmysql関数を扱っている章がありますが、PDOについても書かれており、書き換えることは可能です。その点を除けばほとんどパーフェクトな書籍です。但し、「入門者~初心者」ではなく「初心者~上級者」ぐらいを対象としています。
【安全なWebアプリケーションの作り方】
セキュリティ業界で著名な人が書かれた本です。パーフェクトPHPでもセキュリティ対策に関しては申し分なく学べますが、こちらはセキュリティ対策だけに特化した本です。そのため、PHP以外にもPerlなどのコードも出てきますね。
【PHP逆引きレシピ】
目的からサンプルコードを探せるような本です。内容は確認していませんが、レビューを見る限りはちゃんと書かれていそうですね。
【いきなり始めるPHP】【気づけばプロ並みPHP】は地雷なので買わない方がいいです。
くどくて申し訳ないですが(笑)、こういった本でも
$text = isset($_POST['text']) ? $_POST['text'] : '';
とか書いてることが多いです。が、つい先日filter_input関数がオプションを設定せずとも大変有用であることが分かりましたので、これに関しては http://qiita.com/mpyw/items/2f9955db1c02eeef43ea や http://qiita.com/mpyw/items/346f1789ad0e1b969ebc で紹介している通り
$text = (string)filter_input(INPUT_POST, 'text');
と書くことを強く推奨します。この書き方がデファクトスタンダードになってほしいと願うぐらいですね。
色々ご紹介頂きありがとうございました。
【パーフェクトPHP】は買おうか悩んだ書籍だったので今度買ってみようと思います。
mysql関数で書かれている部分を自分で直すなどしてみても勉強になっていいかもしれませんね。
基本は紹介頂いているサイトを時間あるときに繰り返し読んでいます(笑)
初心者ながらに、へぇーなるほど、と思いあのような感じでまとめて頂いて非常に助かります。
目次のコンテンツにしても更新されるのが楽しみになってしまうくらいです(笑)
また、色々こちらにご質問させて頂くことがあるかと思いますので、ご都合よろしければどうぞよろしくお願いいたします。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Oracle SQL update方法 2 2022/06/22 14:07
- MySQL 書籍の内容はまともでしょうか? 1 2023/01/22 03:07
- MySQL 共通点はあります。何が違うのでしょうか? 1 2023/01/27 05:22
- MySQL PhpMyAdminで作成して実行せよ。 東京23区を、皇居を中心とした4つのエリア(南東, 南西, 1 2023/06/11 11:58
- Oracle 下記のsqlで取得されるレコード以外を取得する方法ありますでしょうか。 SELECT B.番号, B 2 2022/04/20 23:21
- PHP php my adminより取り出したデータ表示 2 2022/06/15 11:56
- Access(アクセス) アクセス 削除するレコードを含んだテーブルを指定してくださいのエラー対処方法 1 2022/11/24 15:01
- Oracle sqlで質問です。 aテーブルとbテーブルがあり、下記のsqlで取得したidとnameに一致しないレ 1 2022/04/20 20:34
- Access(アクセス) アクセス where句を使用して複数条件抽出をするには 2 2022/08/29 13:24
- PostgreSQL 画像とカテゴリーを出力したいのですが、取得の条件を付ける方法がわかりません。 2 2022/05/01 18:03
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
PHP&MySQLでの文字列+数列の一...
-
Q&Aサイトを作成していてURLの...
-
VB.NET エラーになる箇...
-
<VB.NET>INSERT文でDBにデータ...
-
MySQLへの接続
-
Pro*Cの構文エラー
-
MySQLのINSERT時にたまに重複に...
-
実行時エラー3131 FROM 句の構...
-
エクセルVBAについて
-
SQL文が実行できません
-
VBAをつかってクエリの情報を抽...
-
Resource id #3 をフィールドの...
-
SQL文の実行に失敗しました???
-
php データ削除
-
MySQLでデータベースにデータin...
-
PHPで[]の使い方について
-
アラートでyes noを作りたいです。
-
phpのエラーについてです
-
PHPのプルダウンメニューにDBの...
-
checkboxクリック時、SQLを実行...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
JAVA SQLServerException 列名 ...
-
Q&Aサイトを作成していてURLの...
-
<VB.NET>INSERT文でDBにデータ...
-
insert1つの処理でもトランザ...
-
Pro*Cの構文エラー
-
ResultSetインターフェイスでの...
-
データベースに存在するデータ...
-
PHP&MySQLでの文字列+数列の一...
-
VBA ACCESS SQL...
-
phpで複数の検索語を検索対象に...
-
like検索の複数キーワードで、...
-
MySQLのINSERT時にたまに重複に...
-
C# で発生したException.Messag...
-
PHP+PDO+MYSQL で実行されたSQ...
-
PHPのUndefined index や varia...
-
INSERT,DELETEを同時に
-
配列をループさせてUPDATE
-
VB.NET エラーになる箇...
-
php postgres Insert と updat...
-
C#でDBの特定列をUpdate
おすすめ情報