WordPressのカスタマイズ方法やプラグインレビューを中心に、パソコン/動物/植物のことなどを紹介するホームページです

PHP8.0で「Attempt to read property “〇〇” on null in…」というWarning(警告)が出た場合の検証と対処方法(例)

公開日:2021(令和3)年7月4日/最終更新日:

,
WordPressのトラブルシューティング



【景品表示法に基づく表記】ページ内のコンテンツには、商品プロモーションが含まれています

いろいろと調べた結果では、PHP7.0の時とは違い、PHP8.0への更新では、WordPressの動作に何かの影響があったり、パフォーマンスが向上するということはないようですが、それでも今後のことを考え、最新版で問題なく動作するようにしておきたいと考え、記憶ではこのサイトは2021年初旬からPHP8.0で稼働させています。

そんな中、たまたま最近FTPでサーバー内へ接続したところデバッグログファイルがとんでもなく大きいものになっていることに気付きました。

日付はPHP8.0にしてからのもののようで、「デバッグモードをtrueにしてても何も画面上には出なかったのに・・」とブツブツ言いながら開いてみたところ、以下の行が警告としてログへたくさん吐き出されていました

PHP Warning:  Attempt to read property "ID" on null in /テーマまでの階層/functions.php on line 〇〇

直訳解釈すると、「functions.php内の〇行で、空のIDを読み込もうとしました」という内容。警告なのでエラーというわけではないですが、気になるので対象行を確認してみたところ、カスタムフィールドの値がある/なしで判断して処理をさせている部分(コードは後述)でした。コードは合ってるはずなのに・・・。

対処できてみれば「なんだ、そういうことか」という結論ではありましたが、なぜこの警告が出るのかを含め、対処できましたので、備忘録を兼ねて紹介します。

今回は「カスタムフィールドの扱い」での例となりますが、その他の事象でも根本は同じかと思いますので、誰かの参考になれば幸いです。

Warning(警告)が出始めたのはなぜ?

そもそも何でWarning(警告)が出始めたのか?の答えは、PHP7.xからPHP8.0になり、「〇〇がなかったら・・」ということに対して厳格になったこと。

今回の件では、ユーザー定義関数内でカスタムフィールドの値を呼び出す際に、カスタムフィールドがそもそも設定されていないコンテンツであるフロントページ、アーカイブページにアクセスがあったときに「そんなカスタムフィールドはないぞ!」と警告が出てたんです。

以下のようにログにはどこにアクセスされたのかというものではなくプログラム上のこことしか吐き出されないので、ここにたどり着くのにずいぶん苦労しました。

PHP Warning:  Attempt to read property "ID" on null in /テーマまでの階層/functions.php on line 〇〇

気づいたきっかけとなったのは、このサイトのPV数(アクセスリクエスト数)の割に警告行数が圧倒的に少なかったことでした。

要因が分かれば対処もできそう・・ということで早速コードの編集をしました。

コードの改修(例)

警告が出ていたユーザー定義関数は、以下のページで紹介しているサブディレクトリへ英語サイトを追加するためのもの。

問題となったのは、「それぞれの言語ページをカスタムフィールドの有無で判断して、適切なhreflangタグとcanonicalタグを出力しなさい」という以下のコードです。

/**** マルチランゲージのヘッダー出力(主サイト) ****/
function hab_add_multi_lang_header_parent(){
//変数の設定
	global $post;
	$ha_mlang_customfield = get_post_meta($post->ID, 'cf_en_url', true);
	$ha_ima_url=(empty($_SERVER["HTTPS"]) ? "http://" : "https://") . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];
//投稿・固定ページ以外
	if(!is_singular()){
		echo '<link rel="canonical" href="' .$ha_ima_url. '" />';	
//投稿・固定ページでcf_en_urlに入力がある場合
	}elseif($ha_mlang_customfield){
		echo '<link rel="alternate" href="' .$ha_mlang_customfield. '" hreflang="en" />';
		echo '<link rel="alternate" href="' .$ha_ima_url. '" hreflang="ja" />';
		echo '<link rel="canonical" href="' .$ha_ima_url. '" />';
//投稿・固定ページでcf_japanese_urlに入力がない場合
	}else{
		echo '<link rel="canonical" href="' .$ha_ima_url. '" />';	
	}
}
add_action('wp_head', 'hab_add_multi_lang_header_parent',1);

コードの流れ自体は以下のように順番に処理させています。

  1. このユーザー定義関数で使う変数を指定
  2. 固定ページと投稿以外はそのページのURLをcanonicalタグを持たせる
  3. 2以外でカスタムフィールドに値があればそれぞれの言語ページのahreflangと、主サイトのcanonicalタグを持たせる
  4. 3でカスタムフィールドに値がない(この場合英語ページがない)ときは、そのページのURLをcanonicalタグを持たせる
  5. add_actionでwp_head(ヘッダー)へ2~4の結果を出力

そんなに複雑なコードでもないのになぜ?というのが率直な感想です。

しかし、前項の要因で示した通り、カスタムフィールド自体を持たないものに対しては全く無視(感知していない)のがPHP8.0では問題となります。

そこで改修したのが以下のコードです。

/**** マルチランゲージのヘッダー出力(主サイト) ****/
function hab_add_multi_lang_header_parent(){
//フロントページ、アーカイブページ
if(!is_singular() || is_front_page()){
	$ha_ima_url=(empty($_SERVER["HTTPS"]) ? "http://" : "https://") . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];	
	echo '<link rel="canonical" href="' .$ha_ima_url. '" />';	
}

//固定ページでのフロントページを除くすべての投稿と固定ページ
if(is_singular() && !is_front_page()){
	//変数の設定
	global $post;
	$ha_mlang_customfield = get_post_meta($post->ID, 'cf_en_url', true);
	$ha_ima_url=(empty($_SERVER["HTTPS"]) ? "http://" : "https://") . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];
	
if(empty($ha_mlang_customfield)){
//cf_japanese_urlに入力がない場合
	echo '<link rel="canonical" href="' .$ha_ima_url. '" />';	
}else{

//cf_en_urlに入力がある場合	
		echo '<link rel="alternate" href="' .$ha_mlang_customfield. '" hreflang="en" />';
		echo '<link rel="alternate" href="' .$ha_ima_url. '" hreflang="ja" />';
		echo '<link rel="canonical" href="' .$ha_ima_url. '" />';	
}
	}
}

add_action('wp_head', 'hab_add_multi_lang_header_parent',1);

修正前コードとの違いは、以下のように根本的にカスタムフィールドの有無を分けて処理させていることです。

  1. 固定ページと投稿なのかどうかで完全に切り分け
  2. トップページとアーカイブページの場合は、カスタムフィールド以外で必要な変数指定だけして処理
  3. 固定ページと投稿の場合はカスタムフィールドの値の有無に従って処理

上下のコードで、カスタムフィールドの値があるかどうか(空かどうか)の判断や処理の方法が異なりますが、同じ結果になります。

これで、カスタムフィールドを持たないページ(フロントページやアーカイブ)では、カスタムフィールドを持つ持たないの処理をさせないようになるので、警告されることがなくなりました。

もちろんページソースをチェックして、きちんと処理がされているかの確認もしました。


警告や注意のログは特に動作しないというものではないので、「うっとおしいなあ・・」とファイル先頭でエラーを出力しないような記述をしてなんちゃって回避したいという誘惑はありますし、WordPressであればwp-config.phpでdebugをfalseにしておけば何も表示されないのでそのままに師がちですが、そうした対処をしていると、とあるバージョンからいきなり非推奨となったりすることもあり、問題を先送りしているだけですので、きっちりと対処しておくことが大切だと思います。

後述:この警告への対処後一旦error_logを削除したところ、それまでになかったプラグイン関係の警告などが出てくるようになりました。何となく小出し感があり、「ログは全部吐き出されるんじゃないの?」とも思えるのですが、ひとまず出たもの対処をしていきます。

別の警告などもあるので、都度備忘録を残していこうと思ってますので、後の記事をお楽しみに!!