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

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

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

WordPressは、PHPで開発されているオープンソースのブログソフトウェアです。データベース管理システムにはMySQLを用いています。フリーのブログソフトウェアの中では最も人気が高く、PHPとHTMLを使って簡単にテンプレートをカスタマイズすることができます。

PHP

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

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

解決済

PHPで全てのエラーを catch したい(WordPressにお詳しい方へ)

gorimaz
gorimaz

総合スコア26

WordPress

WordPressは、PHPで開発されているオープンソースのブログソフトウェアです。データベース管理システムにはMySQLを用いています。フリーのブログソフトウェアの中では最も人気が高く、PHPとHTMLを使って簡単にテンプレートをカスタマイズすることができます。

PHP

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

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。

2回答

2評価

2クリップ

460閲覧

投稿2022/03/13 14:56

編集2022/03/15 02:11

前提

WordPress特有の仕様についての質問になります。
お詳しい方宜しくお願い致します。

実現したいこと

2つのテーブルを 「厳密に」 LOCK TABLESし、ROLLBACKしたいです。

「厳密に」 とは 「一方のテーブルだけが更新されることを絶対になくしたい(2つのテーブルを絶対に一緒に更新したい)」 という意味です。

一般的に$wpdb->last_errorの場合に自ら throw~catch し、ROLLBACKさせると思います。
今回はPHPのNoticeエラーの場合でも throw~catch し、ROLLBACKさせたいのです。

発生している問題

該当のソースコードのように、Noticeエラーの場合でもそれを throw~catch させようしてset_error_handlerを書きました。

しかしこうすると次の errorMessage のように、なぜかwp_optionswp_commentsLOCK TABLESを要求されます。

(どこにもwp_optionswp_commentsを更新するような処理は書いていないのに、です。)

errorMessage

[13-Mar-2022 14:14:33 UTC] WordPress データベースエラー: Table 'wp_options' was not locked with LOCK TABLES for query SELECT option_value FROM wp_options WHERE option_name = '_site_transient_update_plugins' LIMIT 1 made by require('wp-blog-header.php'), require_once('wp-includes/template-loader.php'), include('/themes/apple/index.php'), get_footer, locate_template, load_template, require_once('/themes/apple/footer.php'), wp_footer, do_action('wp_footer'), WP_Hook->do_action, WP_Hook->apply_filters, wp_admin_bar_render, do_action_ref_array('admin_bar_menu'), WP_Hook->do_action, WP_Hook->apply_filters, wp_admin_bar_updates_menu, wp_get_update_data, get_site_transient, get_site_option, get_network_option, get_option, QM_DB->query [13-Mar-2022 14:14:33 UTC] WordPress データベースエラー: Table 'wp_options' was not locked with LOCK TABLES for query SELECT option_value FROM wp_options WHERE option_name = '_site_transient_update_themes' LIMIT 1 made by require('wp-blog-header.php'), require_once('wp-includes/template-loader.php'), include('/themes/apple/index.php'), get_footer, locate_template, load_template, require_once('/themes/apple/footer.php'), wp_footer, do_action('wp_footer'), WP_Hook->do_action, WP_Hook->apply_filters, wp_admin_bar_render, do_action_ref_array('admin_bar_menu'), WP_Hook->do_action, WP_Hook->apply_filters, wp_admin_bar_updates_menu, wp_get_update_data, get_site_transient, get_site_option, get_network_option, get_option, QM_DB->query [13-Mar-2022 14:14:33 UTC] WordPress データベースエラー: Table 'wp_options' was not locked with LOCK TABLES for query SELECT option_value FROM wp_options WHERE option_name = '_site_transient_update_core' LIMIT 1 made by require('wp-blog-header.php'), require_once('wp-includes/template-loader.php'), include('/themes/apple/index.php'), get_footer, locate_template, load_template, require_once('/themes/apple/footer.php'), wp_footer, do_action('wp_footer'), WP_Hook->do_action, WP_Hook->apply_filters, wp_admin_bar_render, do_action_ref_array('admin_bar_menu'), WP_Hook->do_action, WP_Hook->apply_filters, wp_admin_bar_updates_menu, wp_get_update_data, wp_get_translation_updates, get_site_transient, get_site_option, get_network_option, get_option, QM_DB->query [13-Mar-2022 14:14:33 UTC] WordPress データベースエラー: Table 'wp_comments' was not locked with LOCK TABLES for query SELECT comment_approved, COUNT( * ) AS total FROM wp_comments GROUP BY comment_approved made by require('wp-blog-header.php'), require_once('wp-includes/template-loader.php'), include('/themes/apple/index.php'), get_footer, locate_template, load_template, require_once('/themes/apple/footer.php'), wp_footer, do_action('wp_footer'), WP_Hook->do_action, WP_Hook->apply_filters, wp_admin_bar_render, do_action_ref_array('admin_bar_menu'), WP_Hook->do_action, WP_Hook->apply_filters, wp_admin_bar_comments_menu, wp_count_comments, get_comment_count, QM_DB->query

該当のソースコード

ロック対象の2つのテーブルです。text atag aという値が入っています。

問題のソースコードは後述のupdate()で生じます。

SQL

CREATE TABLE my_texts ( ID BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT ,text VARCHAR(10) NOT NULL ,PRIMARY KEY (ID) ); INSERT INTO my_texts (text) VALUES ('text a'); CREATE TABLE my_tags ( ID BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT ,tag VARCHAR(10) NOT NULL ,PRIMARY KEY (ID) ); INSERT INTO my_tags (tag) VALUES ('tag a');

以下がupdate()です。

上記のtext atag aを、text btag bへ更新しようとしますが、11行目のtag_dataのキーがidでなくxxであるために、59行目で「Notice: Undefined index」を生じさせています。

このエラーを throw~catch させるべく、set_error_handlerを書いたのですが、すると上記の errorMessage が表示されてしまうのが問題です。

PHP

// PHPのNoticeエラーの場合でも throw~catch function exceptions_error_handler($severity, $message, $filename, $lineno) { throw new ErrorException($message, 0, $severity, $filename, $lineno); } // 更新データ $post_data = [ 'id' => 1, 'text' => 'text b', 'tag_data' => [ 'xx' => 1, // 「Notice: Undefined index」 'tag' => 'tag b' ] ]; // 更新を実行 $posted = update( $post_data ); var_dump( $posted ); // 更新の関数 function update( $post_data ){ global $wpdb; // PHPのNoticeエラーの場合でも throw~catch set_error_handler('exceptions_error_handler'); $result = ['status'=>'error']; try { $is_error = null; // テーブルのロック $wpdb->query('SET autocommit=0'); $sql = 'LOCK TABLES my_texts WRITE, my_tags WRITE'; if ( $wpdb->query($sql) === false ) { $is_error = true; $mes = 'テーブルのロックで失敗'; error_log( $mes . ' $sql = ' . json_encode($sql) ); throw new Exception( $mes ); } else { // my_texts の投稿 $sql = 'UPDATE my_texts SET text = %s WHERE ID IN ( %d )'; $prepares = [ $post_data['text'], $post_data['id'] ]; $rows = $wpdb->get_results( $wpdb->prepare( $sql, ...$prepares ) ); if ( $wpdb->last_error ) { $is_error = true; $mes = 'my_texts の get_results で失敗'; error_log( $mes . ' $sql = ' . json_encode($sql) ); throw new Exception( $mes ); } else { // タグ情報 $tag_data = $post_data['tag_data']; // my_tags の投稿 $sql = 'UPDATE my_tags SET tag = %s WHERE ID IN ( %d )'; $prepares = [ $tag_data['tag'], $tag_data['id'] ]; // 「Notice: Undefined index」 $rows = $wpdb->get_results( $wpdb->prepare( $sql, ...$prepares ) ); if( $wpdb->last_error ){ $is_error = true; $mes = 'my_tags の get_results で失敗'; error_log( $mes . ' $sql = ' . json_encode($sql) ); throw new Exception( $mes ); }else{ $result = ['status'=>'ok']; } } } // ロック解除 if( $is_error ){ $wpdb->query('ROLLBACK'); $wpdb->query('UNLOCK TABLES'); error_log( 'ROLLBACK しました' ); }else{ $wpdb->query('COMMIT'); $wpdb->query('UNLOCK TABLES'); error_log( 'COMMIT しました' ); } } catch (Exception $e) { $result = $e->getMessage(); } finally { restore_error_handler(); } return $result; }

試したこと

errorMessage のいう事を素直に聞いてwp_optionswp_commentsLOCK TABLESを次のように実行すると、errorMessage はなくなりました。

PHP

$sql = 'LOCK TABLES my_texts WRITE, my_tags WRITE, wp_options WRITE, wp_comments WRITE';

しかし、そもそもwp_optionswp_commentsLOCK TABLESがなぜ必要なのかわからないので、これであっているのか?とても不安な心境です。

そこで、2つのテーブルを 「厳密に」 LOCK TABLESするような方法として、適切な処理を求めて質問させて頂きました。

PHPのNoticeエラーの場合でもROLLBACKさせるにあたっては、どのような処理が良いのでしょうか?

長い質問で申し訳ございませんが、どなたかWordPressにお詳しい方がいらっしゃいましたら何卒、宜しくお願い致します。

理由不明だが解決した方法(2022/03/14 23:09)

上記「// ロック解除」の処理を下記のようにしたところ、 「厳密に」 LOCK TABLESもでき、errorMessage もなくなりました。しかしなぜ解決したのか?がわからずやはり不安な心境です。正しい処理なのか、他に問題はないのか、大いに疑問です。

原因がお分かりになる方いらっしゃいましたらご教示頂けませんでしょうか。

■ 上記「// ロック解除」の処理↓

php

// ロック解除 if( $is_error ){ $wpdb->query('ROLLBACK'); $wpdb->query('UNLOCK TABLES'); error_log( 'ROLLBACK しました' ); }else{ $wpdb->query('COMMIT'); $wpdb->query('UNLOCK TABLES'); error_log( 'COMMIT しました' ); } } catch (Exception $e) { $result = $e->getMessage(); } finally { restore_error_handler(); } return $result; }

■ 理由不明だが解決した方法↓

php

// ロック解除 $wpdb->query('COMMIT'); error_log( 'COMMIT しました' ); } catch (Exception $e) { $result = $e->getMessage(); $wpdb->query('ROLLBACK'); error_log( 'ROLLBACK しました' ); } finally { restore_error_handler(); $wpdb->query('UNLOCK TABLES'); } return $result; }

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

まだ回答がついていません

会員登録して回答してみよう

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

ただいまの回答率
87.20%

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

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

質問する

関連した質問

同じタグがついた質問を見る

WordPress

WordPressは、PHPで開発されているオープンソースのブログソフトウェアです。データベース管理システムにはMySQLを用いています。フリーのブログソフトウェアの中では最も人気が高く、PHPとHTMLを使って簡単にテンプレートをカスタマイズすることができます。

PHP

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

コードレビュー

コードレビューは、ソフトウェア開発の一工程で、 ソースコードの検査を行い、開発工程で見過ごされた誤りを検出する事で、 ソフトウェア品質を高めるためのものです。