緊張させろ! -PHPでの検証とデータキャスト

はじめに


おそらく、プログラマーは遅かれ早かれデータ検証の問題に直面するでしょう。 同じタイプの検証アルゴリズムの作成に多大な労力を費やしたため、より便利な方法を探すことにしました。 それはかなり前のことであり、それ以来、私は大量の既製のソリューションを使用し、最近まで安全に使用していた独自のソリューションをいくつか開発する機会がありました。

しかし、PHP 5.3に切り替えた後、匿名関数に基づいた新しいバリデーターを書くようになりました。 そして同時に、それらの使用において再度練習します。 将来のクラスに次の要件を設定します。

作業の開始後、このクラスの匿名関数は検証だけでなく、データを適切な種類(たとえば、特定の型)にキャストするためにも使用できることがわかりました。 要件のリスト(「汎用性」)にもう1つ追加したので、クラスの名前をStrainに大胆に変更しました。

最後に何が起こった...以下をお読みください。 ここで、私はオリジナルのソリューションやその他のナンセンスであると主張しません。 このアプローチが好きなら、あなたのプロジェクトでそれを使用し、そうでなければ、いいえ。 必死の倒錯については、記事の最後にソースコードを公開します。

クラスひずみ


上で書いたように、クラスの機能は二重です。 それで使用される匿名関数とそのアプリケーションの両方のタイプを見てみましょう。 もちろん、それらの機能を1つの機能に統合することを妨げるものは何もありません。

私は急いで造られた名前と定義であなたをあまり怖がらないことを望みます。

キャスト関数(FP)

データ変換用のFP(この場合、変数)。 実際、1つのデータを別のデータに変換するためのロジックを含めることができます。 たとえば、すべてをINTEGERに変換する関数を作成します。
Strain :: add ( 'integer' , function ( & $value , $options = null ) { <br/>
$value = ( int ) $value ; <br/>
} ) ;

これは単なる例です。 実際の使用では、ここにビット数の制限を追加します。

次に、この関数の操作を見てみましょう。
$var = '56' ; // ! . <br/>
Strain :: it ( $var , 'integer' ) ; <br/>
var_dump ( $var ) ; <br/>
<br/>
// : int(56)

関数検証(PV)

FVは、特定の条件への準拠についてデータをチェックし、エラーが発生した場合はレポートをスローします。 関数が何も返さない(つまり、NULLを返す)場合、データは正しいです。 例:
Strain :: add ( 'must_be_integer' , function ( & $value , $options = null ) { <br/>
if ( ! is_int ( $value ) ) return true ; <br/>
} ) ;

コメントは冗長です。 関数の関数を見てみましょう:

$var = '56' ; <br/>
var_dump ( Strain :: it ( $var , 'must_be_integer' ) ) ; <br/>
<br/>
// : TRUE

TRUEはエラーを示します。 戻り値の詳細は、Strain :: $ resultで確認できます(この例では、TRUEに一致します)

洗練された例

基本を理解したので、今度はより複雑なStrainのアプリケーションであるオブジェクト検証に進みましょう。

まず、データオブジェクト自体を作成します。 また、たとえば、追加する新しいユーザーに関するデータとします。
$user = ( object ) array ( <br/>
'email' => 'user@site.com' , <br/>
'name' => 'User' , <br/>
'address' => ( object ) array ( <br/>
'city' => 'Default City' , <br/>
'street' => 'Street' <br/>
) <br/>
) ;

そして...正しいデータを含み、必要な構造を持たなければならない何らかの種類のオブジェクトがあり、データベースにそれを投げる前にこれを確認し、すべての検証エラーについて正確に知る必要があります。 幸いなことに、Strainはこの問題を完全に解決できます。
検証が行われるオブジェクトを作成します。 将来、このようなオブジェクトを「データフィルタリングスキーム」(SF)と呼びます。
$valid = ( object ) array ( <br/>
'email' => array ( 'email' , 'UserExists' ) , <br/>
'name' => array ( 'string' , 'regexp' => '/^[A-Za-z0-9 _-]{3,20}$/' ) , <br/>
'address' => ( object ) array ( <br/>
'city' => 'string' , <br/>
'street' => 'string' <br/>
) <br/>
) ;

SFを詳しく見てみましょう。 オブジェクトがチェックされているデータの構造を完全に繰り返しており、プロパティ値のみが何らかの形で「奇妙」であることがすぐにわかります。 皆さんの多くは、このオブジェクトがどのように構成されているかをすでに推測しているはずです。

オブジェクトの各値には、関数名または別のファイルシステムが含まれます。 たとえば、関数名のリストの形式で-関数にパラメーターを渡すことができる混合型の配列。 関数定義の$ options変数が不明瞭であることを覚えていますか? これだ!

それではチェックを始めましょう。 すでに身近な課題があります。
Strain :: it ( $user , $valid ) ; // FALSE

Strain :: $ resultに残っているものを見ることを忘れないでください
object ( stdClass ) #7 (3) {<br/>
[ "email" ] => <br/>
NULL <br/>
[ "name" ] => <br/>
NULL <br/>
[ "address" ] => <br/>
object ( stdClass ) #9 (2) {<br/>
[ "city" ] => <br/>
NULL <br/>
[ "street" ] => <br/>
NULL <br/>
} <br/>
}

ご覧のとおり、オブジェクトはエラーを残すことなくフィルタリングされました。

このメソッドの柔軟性は、Strain :: add()メソッドを使用すると、匿名関数自体だけでなく、上で見たSFも追加できることです。 関数の1つが独自のチェックを開始するときに、再帰も可能です。 (以下を参照)

いくつかのコメント

このクラスをいじり始める前に、さらにいくつかのトリックを学ぶ必要があります。

関数のリストによってデータがチェックされると、何かを返した最初の関数の結果が$ resultになります。 ただし、関数がFALSEを返す場合、結果はNULLになり、チェーンの実行は停止します。 これは、エラーを返さずにチェックを簡単に停止できるようにするために行われます。たとえば、値をNULLにすることはできても、設定することができ、チェックを実行する必要がある場合です。 例:
$valid = array ( 'null' , 'string' , 'length' => array ( 2 , 10 ) ) ;

「null」関数では、NULL値を受け取った場合にFALSEを返すように記述する必要があり、それ以降の検証は実行されず、エラーは表示されません。

同じデータを持つ配列のチェックの実現。
$valid = array ( 'array_of' => array ( 'string' , 'length' => array ( 2 , 10 ) ) ) ;

SFを関数に簡単に転送する方法の例であり、その裁量で使用できます。 この場合、彼らは配列の各要素をチェックします。

別の興味深い例。 条件ORを実装します。
$valid = array ( 'mixed' => array ( 'null' , array ( 'string' , 'length' => array ( 2 , 10 ) ) ) ) ;

この関数によってFALSEを返す必要がない場合のみ、上記のNULLの例と同じです。 同様に、さまざまなXOR、NOR、およびBRRRを実装する関数を思いつくことができます!

結論として、Strain :: it()メソッドの3番目のパラメーターについてお話したいと思います。 データに適用される動作を定義します。 パラメータ値:

0:データ構造を変更しません。
1:フィルター構造で指定されたプロパティをデータ構造に追加します。
2:フィルター構造で指定されていないプロパティをデータ構造から削除します。
3:1と2を一緒に。 (デフォルトでは、この値を使用した場合のみ、オブジェクトの代わりにNULLを入力した場合でも 、フィルタリング後のオブジェクトはSFに類似した構造を持つことが保証されます

つまり クラスは、オブジェクトの不必要なプロパティを削除し、それらに新しいプロパティを追加し、SFに対応しないものを置き換えることができます。 作成されたプロパティはデフォルトでNULLであり、フィルタリングのために送信されます。

おわりに


残念ながら、「array_of」と「mixed」を除いて、ソースに匿名関数を含めませんでした。 いずれにせよ、それらを書くことは非常に簡単であり、誰もがそれらを独自の方法にしたいでしょう。

コードの使いやすさと視覚化のために、FPとPVの名前のスペルを分けることをお勧めします。 たとえば、先頭(または末尾)に「!」文字を含むすべてのFI名を指定します。 または、明示的にロジックを指すパラメーターを考え出します。

重要! 現時点では、クラスはまだテスト中であり、ご自身の責任とリスクでのみ製品で使用できます。

約束どおり、ソースへのリンク:
GitHubのひずみソース

PSそして、誰もがJSに似た何かを必要としますか?

更新:エラーがある場合にit()メソッドがTRUEを返し、エラーがない場合にFALSEを返し、その逆ではない場合、誰かがそのコードを修正できます。 これは、クラスの作業には影響しません。
更新2: check()メソッドがクラスに追加されました。これはit()メソッドに似ていますが、エラーがない場合はTRUEを返し、エラーがある場合はFALSEを返します。
更新3:スキーマで関数を直接指定する機能と、スキームの配列に回路図オブジェクトを挿入する機能を追加しました。これは、簡単に言えばこれを説明できないためです。 コメントに投稿した例の1つ。

Source: https://habr.com/ru/post/J115082/


All Articles