質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

Q&A

解決済

3回答

7681閲覧

Fatal error: Call to a member function prepare() on stringを解決したい

hc130203

総合スコア12

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

0グッド

0クリップ

投稿2019/02/12 04:38

編集2019/02/13 02:20

現在タイムライン掲示板を作成しており、実装が全て終えたのでリファクタリングをしています。
リファクタリングをする項目は以下です。

1.サインインユーザー情報取得
2.投稿情報登録処理
3.いいね件数
3.いいね済みかどうか

2までは無事終えたのですが、3.いいね件数をリファクタリングするとFatal error: Call to a member function prepare() on string in /Applications/XAMPP/xamppfiles/htdocs/batch48/LearnSNS_self/function.php
のエラーがfunction.phpの1サインインユーザー情報取得のリファクタリングに出ます。

他の類似エラーを参考に、文頭に
error_reporting(E_ALL);
ini_set('display_errors', '1');
を追記しましたがエラー表示は変わらぬままでした。

リファクタリングをしない場合だと、同じ場所にエラーが出ないのになぜでしょうか…
ご教示お願い致します。

timeline.php

1<?php 2error_reporting(E_ALL); 3ini_set('display_errors', '1'); 4 5session_start(); 6require('dbconnect2.php'); 7require('function.php'); 8 9// ユーザー登録(リファクタリングする前) 10// $sql = 'SELECT * FROM `users` WHERE `id`=?'; 11// $data = [$_SESSION['LearnSNS_self']['id']]; 12// $stmt = $dbh->prepare($sql); 13// $stmt->execute($data); 14// $signin_user = $stmt->fetch(PDO::FETCH_ASSOC); 15 16// ユーザー登録(リファクタリングした後) 17$signin_user = getUser($dbh,$_SESSION['LearnSNS_self']['id']); 18 19------ 20 21// ユーザーが投稿ボタンを押したとき 22if(!empty($_POST)){ 23 $feed = $_POST['feed']; 24 25 if($feed != ''){ 26     (リファクタリングする前) 27 // $sql = 'INSERT INTO `feeds` (`feed`, `user_id`, `created`) VALUES(?,?,NOW())'; 28 // $data = [$feed, $signin_user['id']]; 29 // $stmt = $dbh->prepare($sql); 30 // $stmt->execute($data); 31     (リファクタリングした後) 32 createFeed($dbh,$feed,$signin_user['id']); 33 34 header('location: timeline.php'); 35 exit(); 36 }else{ 37 $errors['feed'] = 'blank'; 38 } 39} 40------ 41// 何件いいねされているか確認(リファクタリングする前) 42 // $like_sql = 'SELECT COUNT(*)AS `like_cnt` FROM `likes` WHERE `feed_id`=?'; 43 // $like_data = [$record['id']]; 44 // $like_stmt = $dbh->prepare($like_sql); 45 // $like_stmt->execute($like_data); 46 // $like = $like_stmt->fetch(PDO::FETCH_ASSOC); 47 // $record['like_cnt'] = $like['like_cnt']; 48     (リファクタリングした後) 49 $record['like_cnt'] = countLike($dbh,$feed_id); 50

function.php

1<?php 2 3 4 5// サインユーザー情報取得 6function getUser($dbh, $id) { 7 $sql = 'SELECT * FROM `users` WHERE `id`=?'; 8 $data = [$id]; 9 $stmt = $dbh->prepare($sql);###←★エラーが出ていると言われる場所 10 $stmt->execute($data); 11 return $stmt->fetch(PDO::FETCH_ASSOC); 12} 13 14 15// // 投稿情報登録処理 16function createFeed($dbh,$feed,$user_id){ 17 $sql = 'INSERT INTO `feeds`(`feed`,`user_id`,`created`) VALUES(?,?,NOW())'; 18 $data = [$feed,$signin_user['id']]; 19 $stmt = $dbh->prepare($sql); 20 $stmt->execute($data); 21} 22 23// いいね件数 24$dbh = ""; 25$feed_id = ""; 26function countLike(){ 27 $sql = "SELECT COUNT(*)AS `like_cnt` FROM `likes` WHERE `feed_id`=?"; 28 $data = [$feed_id]; 29 $stmt = $dbh->prepare($sql); 30 $stmt->execute($data); 31 $result = $like_stmt->fetch(PDO::FETCH_ASSOC); 32 return $result['like_cnt']; 33} 34 35

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2019/02/12 05:18

[ ]### ←★エラーが出ていると言われる場所 ↑全角空白が入っています。再現確認する上での弊害となるので調整いただけたらと。
guest

回答3

0

php

1$dbh = "";

ここで文字列を代入した$dbhに対して、メソッドが呼ばれてしまっているようです。

投稿2019/02/12 04:41

maisumakun

総合スコア145183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hc130203

2019/02/13 02:21

ご回答ありがとうございます!
guest

0

ちゃんとやるならclassで機能をわけた方がよいでしょう
$dbhがきちんと設定されていなければそのメソッドである
prepareは実行できません

投稿2019/02/12 04:52

yambejp

総合スコア114769

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hc130203

2019/02/13 02:23

すみません、まだ初級者なので$dbh設定をわかっていませんでした。 ありがとうございます!
guest

0

ベストアンサー

別観点から(重複するところもあるけど)
countLike()は$dbhも$feed_idも渡してないので動きませんが大丈夫ですか?

yambejpさんの回答も含めて共通化はある程度きちんと考えた方が良いです。

$dbhはおそらくdbconnect2.phpに書かれているものだと思いますが、おおおよそnew PDO()の結果ですよね。
引数は基本的に「処理によって変わるもの」を渡すべきと考えます。「変数」ですし。
接続情報自体はそもそも場合によって変わるわけではありませんので、毎回引数で渡すくらいならglobalキーワードで持っていったほうがまだ自然にも思います。

本来やるべき姿としてはnew PDO()と同じような構成ではないかなと。
newするときの引数でコンストラクタによって接続を確立して、その後、prepare()なりなんなり機能を利用していますよね?
それと同じく、「DB関係の処理をまとめたクラス」を作って、それぞれ役割を渡すべきではないかなと。
PDOと同じくコンストラクタで接続を確立しておいてプロパティに接続情報を持っておけばそれを参照するように各function冒頭で書いておけば毎回引数で渡すようなことはしなくて済みますし。

※ざっくり作ったので動作未検証。本来は各functionのアクセス権とか引数と返り値の型宣言まできちんと入れるべき

php

1class db{ 2 protected $dbh = null; 3 4 function __construct(){ 5 try{ 6 $this->dbh= new PDO("XXX");//ここは元の接続処理をそのまま移行していいかなと 7 }catch(PDOException $e){ 8 var_dump($e); 9 } 10 11 } 12 13 // サインユーザー情報取得 14 function getUser($id) { 15 $sql = 'SELECT * FROM `users` WHERE `id`=?'; 16 $data = [$id]; 17 $stmt = $this->dbh->prepare($sql); 18 $stmt->execute($data); 19 return $stmt->fetch(PDO::FETCH_ASSOC);//PDO::FETCH_ASSOCしかしないのであれば毎回書くのではなくそれだけで1つ関数作ってreturn $stmt->fetch(PDO::FETCH_ASSOC);するだけの関数作るのもあり。 20 } 21 22 23 // 投稿情報登録処理 24 function createFeed($feed,$user_id){ 25 $sql = 'INSERT INTO `feeds`(`feed`,`user_id`,`created`) VALUES(?,?,NOW())'; 26 $data = [$feed,$signin_user['id']]; 27 $stmt = $this->dbh->prepare($sql); 28 $stmt->execute($data); //何も返さないのはNG。insertは確か成功したかどうかが返るはずなので何かしら返したほうがいいし「確実に成功する」前提での作りは良くないのでこちらもtry-catchで囲ってしっかりExceptionを捕捉すべき 29 } 30 31 // いいね件数 32 function countLike($feed_id){ 33 $sql = "SELECT COUNT(*)AS `like_cnt` FROM `likes` WHERE `feed_id`=?"; 34 $data = [$feed_id]; 35 $stmt = $this->dbh->prepare($sql); 36 $stmt->execute($data); 37 $result = $stmt->fetch(PDO::FETCH_ASSOC); //元のコード、変数名間違えてますよ。修正しました。 38 return $result['like_cnt']; 39 } 40 /* 41SQL作る→$dataに?の分の変数作る→preareする→executeに$data渡して実行 42まで同じならここも「executeするまでの処理」を共通化したものを作ったほうがスッキリすると思う。 43要は$sql作って、$dataを配列で渡せば良いので。 44同じ処理が2回3回以上でてくるようなら共通化を検討しましょう。 45*/ 46} 47

使うとき

php

1$db = new db(); 2 3 4$signin_user = $db->getUser($_SESSION['LearnSNS_self']['id']);

投稿2019/02/12 05:27

編集2019/02/12 05:36
m.ts10806

総合スコア80850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hc130203

2019/02/13 03:06

ご回答、丁寧に解説していただきありがとうございます! すみません、まだ初心者ですので追加で質問させてください。 ① mts10806さんが示してくださったclass dbの$this->dbh= new PDO("XXX");には何を入れるのが正解なのでしょうか? mts10806さんのおっしゃるとおり、dbconnect2.phpには $dsn = 'mysql:dbname=LearnSNS_self;host=localhost'; $user = 'root'; $password=''; $dbh = new PDO($dsn, $user, $password); // SQL文にエラーがあった際、画面にエラーを出力する設定 $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $dbh->query('SET NAMES utf8'); で接続情報を書いています。 $this->dbh= new PDO("dbconnect2.php");にすると エラー:object(PDOException)#3 (8) { ["message":protected]=> string(24) "invalid data source name" ["string":"Exception":private]=> string(0) "" ["code":protected]=> int(0) ["file":protected]=> string(72) "/Applications/XAMPP/xamppfiles/htdocs/batch48/LearnSNS_self/function.php" ["line":protected]=> int(8) ["trace":"Exception":private]=> array(2) { [0]=> array(6) { ["file"]=> string(72) "/Applications/XAMPP/xamppfiles/htdocs/batch48/LearnSNS_self/function.php" ["line"]=> int(8) ["function"]=> string(11) "__construct" ["class"]=> string(3) "PDO" ["type"]=> string(2) "->" ["args"]=> array(1) { [0]=> string(14) "dbconnect2.php" } } [1]=> array(6) { ["file"]=> string(72) "/Applications/XAMPP/xamppfiles/htdocs/batch48/LearnSNS_self/timeline.php" ["line"]=> int(16) ["function"]=> string(11) "__construct" ["class"]=> string(2) "db" ["type"]=> string(2) "->" ["args"]=> array(0) { } } } ["previous":"Exception":private]=> NULL ["errorInfo"]=> NULL } Fatal error: Call to undefined method db::getUser() in /Applications/XAMPP/xamppfiles/htdocs/batch48/LearnSNS_self/timeline.php on line 18 がでます。 $this->dbh= new PDO($dsn, $user, $password);にすると上記のエラーに加え、 Notice: Undefined variable: dsn in /Applications/XAMPP/xamppfiles/htdocs/batch48/LearnSNS_self/function.php on line 8 Notice: Undefined variable: user in /Applications/XAMPP/xamppfiles/htdocs/batch48/LearnSNS_self/function.php on line 8 と、また定義されていないと言われます。 ②class dbはfunction.phpの中で間違ってないでしょうか。 ③いいね件数取得の feed_id = ""; dbh = ""; は残したままでよいでしょうか? かなり質問が多くなってしまい申し訳ないです。 エラーを読んだのですが難しくて…。 よろしくお願い致します。
m.ts10806

2019/02/13 03:53

① 省略していますので自身の接続情報を入れてください。 PDO("dbconnect2.php")ではないです。dbconnect2.phpという文字列を入れても何も起きません。 dbconnect2.phpの中に書かれている下記をそのまま置き換えればよいでしょう。 $this->dbh= new PDO("XXX"); ↓ $dsn = 'mysql:dbname=LearnSNS_self;host=localhost'; $user = 'root'; $password=''; $this->dbh = new PDO($dsn, $user, $password); ② できればclass名とファイル名はあわせてください。 というか役割によってファイルをわけるようにしてください。 functions.phpだと全部盛りになってしまってなんでもかんでも そこに放り込んでいくとファットコード(何かよくわからないけど巨大なすんごい行数のコード)になります。 ③ 不要です。使ってませんよね。残しておく意味はないです。
hc130203

2019/02/13 05:12

ありがとうございます! 先ほどのエラーたちはなくなりました。 最初に示してくださった --- $db = new db(); $signin_user = $db->getUser($_SESSION['LearnSNS_self']['id']); --- は、timeline.phpのサインインユーザーであっていますか? エラー: Fatal error: Call to undefined method db::getUser() in /Applications/XAMPP/xamppfiles/htdocs/batch48/LearnSNS_self/timeline.php on line 18 が出てしまいました。 こちら↓を参考にしたのですが、$dbはちゃんと定義はしてあると思うのですが… https://marycore.jp/prog/php/call-to-undefined-method/
m.ts10806

2019/02/13 05:38

>timeline.phpのサインインユーザーであっていますか? 知りません。timeline.phpが提示されていませんし。 現在の質問者さんのコードが分かりませんのでこれだけでは何とも言えません。 もし本件が解決したのでしたら、一度この質問を閉じられて、新しい質問を立ててこちらの質問を関連質問としてリンクを置かれてはどうでしょうか。 コメントを見る限りだと「完全に作り直しである」という認識がないまま、適当に自分のコードを残してしまっているような気がします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問