回答編集履歴

7

修正

2019/02/22 02:31

投稿

m.ts10806
m.ts10806

スコア80850

test CHANGED
@@ -68,7 +68,7 @@
68
68
 
69
69
  `object(PDOStatement)#3 (1) { ["queryString"]=> string(XX) "SELECT ID FROM TB_LIST" } `
70
70
 
71
- に返ってきていたら成功しています。
71
+ のように返ってきていたら成功しています。
72
72
 
73
73
  もし、`bool(false)` とだけ出ていたら失敗しています。
74
74
 
@@ -130,7 +130,9 @@
130
130
 
131
131
 
132
132
 
133
- 出ていない=queryはきちんと届けられていて成功している わけですがキャストをしてしまうことで無理やりコードを正常化してしまっていることになります。
133
+ 出ていない=queryはきちんと届けられていて成功している わけですが
134
+
135
+ キャストをしてしまうことで変数の型が変わります。
134
136
 
135
137
  foreachの前でこうしてみましょう。
136
138
 
@@ -178,6 +180,20 @@
178
180
 
179
181
 
180
182
 
183
+ foreach()には配列とオブジェクトのみ使えますが、
184
+
185
+ 何が入っているか確かめていない配列を(array)でキャストすることによって
186
+
187
+ 無理やりコードを正常化してしまっていることになります。
188
+
189
+ つまり、気づけたはずのエラーが気づけなくなるわけです。
190
+
191
+ これに限らずキャストが必要な場面はほとんどありません。
192
+
193
+ キャストするくらいなら変数が想定の情報を持ってきているかを確認した上で実行するように組んでください。
194
+
195
+
196
+
181
197
  # 2.配列の添え字で使うIDとidは別物。データベースの設定と合ってる? について
182
198
 
183
199
 

6

修正

2019/02/22 02:31

投稿

m.ts10806
m.ts10806

スコア80850

test CHANGED
@@ -66,7 +66,7 @@
66
66
 
67
67
  これでvar_dump()の結果が
68
68
 
69
- `object(PDOStatement)#3 (1) { ["queryString"]=> string(XX) "SELECT ID FROM TB_LIST" }
69
+ `object(PDOStatement)#3 (1) { ["queryString"]=> string(XX) "SELECT ID FROM TB_LIST" } `
70
70
 
71
71
  に返ってきていたら成功しています。
72
72
 

5

修正

2019/02/22 01:14

投稿

m.ts10806
m.ts10806

スコア80850

test CHANGED
@@ -48,7 +48,7 @@
48
48
 
49
49
  var_dump($stmt);
50
50
 
51
- if($stmt){
51
+ if(!$stmt){
52
52
 
53
53
  die('失敗');
54
54
 

4

修正

2019/02/22 00:57

投稿

m.ts10806
m.ts10806

スコア80850

test CHANGED
@@ -30,6 +30,24 @@
30
30
 
31
31
  ```php
32
32
 
33
+ if(!$stmt){
34
+
35
+ die('失敗');
36
+
37
+ }
38
+
39
+ //成功したときの処理
40
+
41
+ ```
42
+
43
+
44
+
45
+ もちろん、デバッグのために$stmtが何をもっているか確認するのは必須です。
46
+
47
+ ```php
48
+
49
+ var_dump($stmt);
50
+
33
51
  if($stmt){
34
52
 
35
53
  die('失敗');
@@ -42,24 +60,6 @@
42
60
 
43
61
 
44
62
 
45
- もちろん、デバッグのために$stmtが何をもっているか確認するのは必須です。
46
-
47
- ```php
48
-
49
- var_dump($stmt);
50
-
51
- if($stmt){
52
-
53
- die('失敗');
54
-
55
- }
56
-
57
- //成功したときの処理
58
-
59
- ```
60
-
61
-
62
-
63
63
  ※確認できたらいったん行頭に//をつけてコメントアウトしておくと良いです。
64
64
 
65
65
 

3

修正

2019/02/22 00:57

投稿

m.ts10806
m.ts10806

スコア80850

test CHANGED
@@ -18,7 +18,7 @@
18
18
 
19
19
 
20
20
 
21
- # 1.について
21
+ # 1.キャスト(array)が邪魔について
22
22
 
23
23
  [PDO::query](http://php.net/manual/ja/pdo.query.php)の返却値は「PDOStatement オブジェクト」OR「false」です。
24
24
 
@@ -170,11 +170,15 @@
170
170
 
171
171
  ```
172
172
 
173
-
173
+ キャストを含めたコーディングで注意すべき点は下記のような記事が参考になります。
174
+
174
-
175
+ - [初心者を戒めるPHP](https://qiita.com/tadsan/items/fb496e450fc27c8c4494)
176
+
175
-
177
+ - [モダンPHPアンチパターン](https://qiita.com/tadsan/items/157969b338fd8b782b21)
176
-
178
+
179
+
180
+
177
- 2.について
181
+ # 2.配列の添え字で使うIDとidは別物。データベースの設定と合ってる? について
178
182
 
179
183
 
180
184
 

2

修正

2019/02/22 00:55

投稿

m.ts10806
m.ts10806

スコア80850

test CHANGED
@@ -1,3 +1,13 @@
1
+ DBに接続する際には下記のような記事が参考になります。
2
+
3
+ - [PHPでデータベースに接続するときのまとめ](https://qiita.com/mpyw/items/b00b72c5c95aac573b71)
4
+
5
+
6
+
7
+ ですが、
8
+
9
+
10
+
1
11
  解決したいだけでしたら確認する点は二点です。
2
12
 
3
13
 
@@ -8,4 +18,236 @@
8
18
 
9
19
 
10
20
 
11
- **途中投稿ししまいました。追記中です。少々お待ちください。**
21
+ # 1.につい
22
+
23
+ [PDO::query](http://php.net/manual/ja/pdo.query.php)の返却値は「PDOStatement オブジェクト」OR「false」です。
24
+
25
+ つまり、返却値を確認してfalseでなければ、一応、queryは無事届けられたと思って良いです。
26
+
27
+ try-catchを随所に書かれていますが、それは**プログラムが必ず成功するわけではないという前提**で書かれているもののはずです。
28
+
29
+ で、あれば、そのqueryも**必ず成功するわけではないという前提**で対応しましょう。
30
+
31
+ ```php
32
+
33
+ if($stmt){
34
+
35
+ die('失敗');
36
+
37
+ }
38
+
39
+ //成功したときの処理
40
+
41
+ ```
42
+
43
+
44
+
45
+ もちろん、デバッグのために$stmtが何をもっているか確認するのは必須です。
46
+
47
+ ```php
48
+
49
+ var_dump($stmt);
50
+
51
+ if($stmt){
52
+
53
+ die('失敗');
54
+
55
+ }
56
+
57
+ //成功したときの処理
58
+
59
+ ```
60
+
61
+
62
+
63
+ ※確認できたらいったん行頭に//をつけてコメントアウトしておくと良いです。
64
+
65
+
66
+
67
+ これでvar_dump()の結果が
68
+
69
+ `object(PDOStatement)#3 (1) { ["queryString"]=> string(XX) "SELECT ID FROM TB_LIST" }
70
+
71
+ に返ってきていたら成功しています。
72
+
73
+ もし、`bool(false)` とだけ出ていたら失敗しています。
74
+
75
+
76
+
77
+ ここで1点アドバイス。
78
+
79
+
80
+
81
+ 今のコーディング内容ではPDOExceptionをちゃんと拾うようにできていません。
82
+
83
+
84
+
85
+ `new PDO()`する際に幾つか引数をつけて実行していると思いますが
86
+
87
+ [PDO](http://php.net/manual/ja/pdo.construct.php)の引数、今のところは$dsn,$username,$passwordまでしか入れてませんよね?
88
+
89
+ その次の$optionに注目してください。
90
+
91
+ > ドライバ固有の接続オプションを指定するキー=> 値の配列。
92
+
93
+
94
+
95
+ ここで色々なOPTIONを指定することができますが、その中にATTR_ERRMODEというのがあります。([属性の説明](http://php.net/manual/ja/pdo.setattribute.php))
96
+
97
+ ここでPDO::ERRMODE_EXCEPTIONを指定することできちんとExceptionを拾うようになります。
98
+
99
+
100
+
101
+ 最初に提示したQiitaの参考記事では下記のように$optionsを指定していますね。
102
+
103
+ ```
104
+
105
+ [
106
+
107
+ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
108
+
109
+ PDO::ATTR_EMULATE_PREPARES => false,
110
+
111
+ ]
112
+
113
+ ```
114
+
115
+
116
+
117
+ 上記をPDO()接続時の引数に指定した上でもう一度実行してみてください。
118
+
119
+
120
+
121
+ そこで`エラーSQLSTATE[・・・・`のようなエラーメッセージが出てきたらその先のエラーコードとエラー理由を確認しましょう。
122
+
123
+ 参考:[エラーメッセージの読み方と対処, 検索や質問の原則](https://qiita.com/cannorin/items/eb062aae88bfe2ad6fe5)
124
+
125
+
126
+
127
+
128
+
129
+ 出ていないのでしたらようやく「キャスト(array)が邪魔」の対応ができます。
130
+
131
+
132
+
133
+ 出ていない=queryはきちんと届けられていて成功している わけですがキャストをしてしまうことで無理やりコードを正常化してしまっていることになります。
134
+
135
+ foreachの前でこうしてみましょう。
136
+
137
+ ```php
138
+
139
+ var_dump((array)$stmt);
140
+
141
+ ```
142
+
143
+
144
+
145
+ 結果は下記のようになっていませんか?
146
+
147
+ `array(1) { ["queryString"]=> string(XX) "SELECT ID FROM TB_LIST" }`
148
+
149
+
150
+
151
+ PDO::queryで折角取得できたPDOStatementがなくなってしまっています。
152
+
153
+ つまり、SELECT文の実行結果は「結果セット」つまり、データが入っているとイコールなので、そこがなくなってしまうと
154
+
155
+ 実行結果もなくなってしまうということになります。
156
+
157
+
158
+
159
+ 実行結果をそのまま素直にループさせれば良いです。
160
+
161
+ ```php
162
+
163
+ foreach ($stmt as $row) {
164
+
165
+ // 出力
166
+
167
+ echo $row['ID'];
168
+
169
+ }
170
+
171
+ ```
172
+
173
+
174
+
175
+
176
+
177
+ 2.について
178
+
179
+
180
+
181
+ これに加えてもう1つ確認すべき点があります。
182
+
183
+ 一応(array)キャストをすることで下記のような配列ができるのでforeachはできるはず。
184
+
185
+ `array(1) { ["queryString"]=> string(XX) "SELECT ID FROM TB_LIST" }`
186
+
187
+
188
+
189
+ コードでは`$row['ID']`を参照しようとしていますが、そのようなデータありません。
190
+
191
+ 連想配列そのまま回しているので$rowだけで`SELECT ID FROM TB_LIST`が取れるはず。
192
+
193
+ PHPにおいて、存在しないキーを参照しようとすると`Warning: Illegal string offset '指定名' `または`Notice: Undefined index`のようなエラーが出ます。
194
+
195
+ ※きちんとケースはありますが、どちらかが出てたら参照が間違っているという理解でいたらいいです
196
+
197
+
198
+
199
+ おそらく質問者さんの実行環境ではエラー表示が制御されているのではないでしょうか。
200
+
201
+
202
+
203
+ 学習段階、開発途中段階のコードでは何が起きるか分からないので、全てのレベルのエラー表示をするようにしておくことを強くすすめます。
204
+
205
+ - [エラー表示ON](https://qiita.com/shotets/items/3c95aef631b2c5eadae5)
206
+
207
+
208
+
209
+
210
+
211
+ 1.を全て対応した後でも想定通りの結果が出ない場合はここまでやってみてください。
212
+
213
+ 配列の添え字のキーを間違えていないか?大文字と小文字は別物です。
214
+
215
+
216
+
217
+ ```php
218
+
219
+ $hoge["a"] = "hello";
220
+
221
+ echo $hoge["d"]; // Notice: Undefined index: A
222
+
223
+ echo $hoge["A"]; // Notice: Undefined index: A
224
+
225
+ echo $hoge["a"]; // Hello
226
+
227
+
228
+
229
+ ```
230
+
231
+
232
+
233
+ ----
234
+
235
+
236
+
237
+ 以下、今後を見据えた場合の蛇足。
238
+
239
+
240
+
241
+ 0. データを出力するときは[HTMLエスケープ](http://php.net/manual/ja/function.htmlspecialchars.php)をしよう。
242
+
243
+ なぜそうすべきかというのは[XSS](https://gihyo.jp/dev/serial/01/javascript-security/0002)とかで調べると良いです。
244
+
245
+ 0. 今後、もしかしたら検索条件などを指定してデータを取得する機会があるかもしれませんが、そのときはSQLのエスケープは必ず行おう。PDO::queryよりも[PDO::prepareで「プリペアドステートメント」をセットしてからのbindValue](https://qiita.com/mpyw/items/b00b72c5c95aac573b71#pdoprepare--pdostatementbindvalue--pdostatementexecute-%E3%81%AE3%E3%82%B9%E3%83%86%E3%83%83%E3%83%97%E3%81%A7%E3%82%AF%E3%82%A8%E3%83%AA%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B)がおすすめです。
246
+
247
+ なぜそうすべきかは[SQLインジェクション](https://academy.gmocloud.com/advance/20150608/700)とかで調べると良いです。
248
+
249
+
250
+
251
+
252
+
253
+ 以上。

1

途中投稿・・・

2019/02/22 00:52

投稿

m.ts10806
m.ts10806

スコア80850

test CHANGED
@@ -5,3 +5,7 @@
5
5
  0. キャスト(array)が邪魔
6
6
 
7
7
  0. 配列の添え字で使うIDとidは別物。データベースの設定と合ってる?
8
+
9
+
10
+
11
+ **途中投稿してしまいました。追記中です。少々お待ちください。**