奇特なブログ

「殊勝に値する行いや心掛け」を意味する、奇特な人になる為のブログです

小さな技術ネタ8つ

一つ一つが小さいので、まとめましたよ。


1.switchの分岐

もう、すっかりお約束かと思うんですが、

「switch($data)」と書いた時に、「==」で比較されますよっていうやつ。

で、以下の様な解決策が、提示されてますと。

ケースごとに異なる処理を、ポリモーフィズムで表現する(生PHPで) - Qiita

あるいは、上記の参考リンクに書かれている以下とか。

PHP :: switch の case 文で厳密な型比較をする [Tipsというかメモ]

・・・これなら別に、if~elseでもよくない?と思ってしまったんですよね(苦笑)

いや、別の記事にもリンク貼った事ありますが、

個人的に、以下の様なコードもあるので、stateパターンを使う事に否定的ってわけじゃないんですけど。

final_magic/view.php at master · kitoku-magic/final_magic · GitHub

ただ、分岐した「後」の、各クラス毎の処理の差異が殆どない様なケースだったら、

別に、そこまでしなくても良いんじゃないかなぁと。

「今はまだ少ないけど、これから差異が増える(この考えもYAGNI観点からは微妙ですが)」のが、

「確定」レベルならアリでしょうけど、そうじゃないのにって所じゃないですかね。

単に、「何がなんでもデザパタを適用する」的な、信者的な考えが苦手って話な気もしますけどね(苦笑)


2.HTMLのnameやDBのカラム名の、スネーク・キャメルの統一

結構、昔から時々感じていたんですけどね。

「user_id」と「userId」が混ざってますと。

で、混ざっているが故に、以下の様なコード(あくまで一例)をわざわざ書く必要があると。

$data = array(
  'user_id' => $_POST['userId'],
);
$entity->setUserId($_POST['user_id']);
$result = array(
  'userId' => $row['user_id'],
);
$entity->setUserId($row['user_id']);

とりあえず、最も多そうなケースとして、

「DBのカラムでuserIdというケースを見た事がない」のは、大文字・小文字を区別しない以下が原因かなと。

【MySQL】カラム名の大文字、小文字の区別 at softelメモ

といっても、別に「userId」というカラム名にしても良いじゃないかとも思うんですが、一旦置いておきましょう。

ただ、そうなると命名を統一するには「set_user_id()」となり、ここに違和感を感じる人が多いんだろうと。

いや、「setUserId」だろう?なんか、変じゃね?と。

といっても、set_user_idにしたら、何か問題が起きるのかという所なんでしょうと。

・・・何が理由があるんですかね?いや、命名が統一されているケースは、おそらく一度も見た事が無いので。
問題があるなら、統一されてなくても全然良いんですけど。

個人的にはスネーク派ですが、何も問題が無いなら「どちらかに統一」をって思うんですよね。

統一されていれば、キャネルでも良いよと。


3.DateTime::createFromFormat

これはマニアックな気がしますが、例えば以下の様(PHP7.2.10)に書くと。

<?php

// ケース1、問題無し
$datetime = new DateTime('24:59:59');
var_dump($datetime);

// ケース2、問題無し
$datetime = new DateTime();
$datetime->setTime(25, 0, 0);
var_dump($datetime);

// ケース3、問題無し
$datetime = DateTime::createFromFormat('H:i:s', '25:00:00');
var_dump($datetime);

// ケース4、指定されているフォーマットと違うので、$datetimeがfalseになる
$datetime = DateTime::createFromFormat('His', '25:00:00');
var_dump($datetime);

// ケース5、Fatal Error
$datetime = new DateTime('25:00:00');
var_dump($datetime);

$ php datetime_test.php

object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2018-11-25 00:59:59.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(10) "Asia/Tokyo"
}
object(DateTime)#2 (3) {
  ["date"]=>
  string(26) "2018-11-25 01:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(10) "Asia/Tokyo"
}
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "2018-11-25 01:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(10) "Asia/Tokyo"
}
bool(false)

Fatal error: Uncaught Exception: DateTime::__construct(): Failed to parse time string (25:00:00) at position 0 (2): Unexpected character in 
・・・以下、省略

となるので、「DateTime::createFromFormat()」が良いんじゃないの?と。

特にケース4が良いと思いますね。

応用すると、以下の様な事も出来ますし。

【PHP】DateTimeクラスでcheckdate()より汎用性のある日付チェックを行う - Qiita

注意点としては、上記の場合「年月日が翌日になる」って所でしょうか。


4.DateTime同士の日時比較

↑の3と関連しているんですが。

PHP: DateTime::diff - Manual


注意:

PHP 5.2.2 以降では、DateTime オブジェクトを 比較演算子 で比較できるようになりました。

ちょっと意外だったので、驚きましたね。

実例は、上記リンク先に書いてあるので、省略します。


5.stringとintの比較時のキャスト

例えば「リクエストパラメータの値(string)と、DBから取得してきた値(最近は、intのケースが多いか?)」を比較する時に、

「intをstringにキャスト」するか、「stringをintにキャストするか」的な話なんですが、

<?php

$request_parameter = '1a';
$db_value = 1;

if ((int) $request_parameter === $db_value)
{
  echo "string to int\n";
}

if ($request_parameter === (string) $db_value)
{
  echo "int to string\n";
}

$ php cast_test.php
string to int

と通ってしまうので、「intの方をstringにキャストする」が良いかなと。

といっても、値が大きくてfloatの場合、

stringにキャストしたら以下の様になるので、そこは別途注意でしょうけどね。

<?php

$db_value_int = PHP_INT_MAX;
$db_value_float = PHP_INT_MAX + 1;
var_dump($db_value_int);
var_dump($db_value_float);
var_dump((string) $db_value_int);
var_dump((string) $db_value_float);
var_dump(sprintf('%u', $db_value_int));
var_dump(sprintf('%u', $db_value_float));

$ php cast_test.php
int(9223372036854775807)
float(9.2233720368548E+18)
string(19) "9223372036854775807"
string(19) "9.2233720368548E+18"
string(19) "9223372036854775807"
string(19) "9223372036854775808"


6.NOT NULLが付いていない

「数値型の0や、文字列型の空文字の値に、特別な意味があったり、既存との値の体系的に、どうしてもNULLが必要」

ってケースぐらいですかね、NULLを許容する必要があるのって。

それすら微妙でしょうか?

user_idが0、日付が0001-01-01(ここは、さほど調べてませんが)、名前が空文字、statusが0・・・

statusが0のケースが時々って所じゃないですかね。

新規で作るならstatusが0の場合にも意味を持たせない方が良いと思いますけど。

書き切れないぐらい色々なケースがあるでしょうけど、やっぱりNOT NULLを付ける形が良いんじゃないかなと。

いや、単純に以下の様な事をいちいち意識したくないってのが、本音ですけどね(笑)

NULL撲滅委員会


7.O/Rマッピングについて

先日、以下の記事が盛り上がってましたので。

O/Rマッピングは百害あって一利なし! - Qiita

これ、以下の記事では主題じゃなかったので書かなかったですが。

続・MVCのMのクラス設計草案など - 奇特なブログ

以下の様に、「SQLは書くけど、全部じゃないよ」的なO/Rマッパーじゃダメなんですかね。

other/order_repository_impl.php at master · kitoku-magic/other · GitHub

「和洋折衷」というか、良いとこ取りみたい感じですけど(笑)

あと、直でSQLを書いているというルール違反については、

「SELECT 」「INSERT INTO 」「UPDATE 」「DELETE FROM 」とかでGREPして、

以下のクラス「以外」がヒットしたら「おや?」とかね。

other/rdbms_storage_handler.php at master · kitoku-magic/other · GitHub

なので、既存のFWでも、あまりガッツリ使わなければ良いんじゃないかと思いますね。

要は、「変わったSQLを書くときに、どうか?」ってのがポイントなんじゃないのかと。

以下の様なSQLを、業務で書く必要があったらとか。

other/reservation_double_booking_check.php at master · kitoku-magic/other · GitHub


8.SQLで取ってきたデータに、使いたいカラムが含まれていない

上記の7とも少し絡むんですが、

SQLで項目が指定可能だと良い」と。

いや、別にどうって事ない話なんですが。

というのも、項目が固定だと「不要だと思ったら、後で必要になった」的なケースが何度も起きて、

その度にソース修正するの?と。

だから、常に全項目取得(パフォーマンスはありますが、ここはさほど)で良いんでは?とも思いますが、

流石に不要項目(上記の通り、不要だと思ったら、後で必要になったりもしますがね)があまりにも多過ぎる場合にはとも思いまして。

なので、「項目を指定しなければ全項目取得だが、項目を指定する事も出来る」が良いかなと。

あと、別にコレSQLに限らず、外部のAPIを呼び出して、

必要なデータを取得する時に、項目が指定可能とかも。

外部APIの場合は、項目を細かく指定するのは難しいかもしれないので、

「全項目フラグ=true or false」みたくなるかもしれないですけどね。


以上です。

ここまで書き終えて、以下の話じゃないけど、

基本的に「大したことじゃない事」に、頭を使いたくないみたいですね(苦笑)

どこにリソースを突っ込むのか? って選択は大事だよねぇ - gallu’s blog

あと、本日のBGM(曲の途中から)は・・・以下かな(笑)

Within Temptation - Whole World is Watching ft. Dave Pirner - YouTube

Radiohead - 2+2=5 - YouTube