ホームページ > バックエンド開発 > PHPチュートリアル > PHP_PHP教程のマジックメソッドを解読する

PHP_PHP教程のマジックメソッドを解読する

WBOY
リリース: 2016-07-13 17:53:57
オリジナル
1114 人が閲覧しました

PHP には、オブジェクト指向プログラミングで非常に巧妙なトリックを実行できる「魔法の」メソッドが多数用意されています。これらのメソッドは 2 つのアンダースコア接頭辞 (__) で識別され、特定の条件が満たされたときに自動的に呼び出されるインターセプターとして機能します。マジック メソッドは非常に便利な機能を提供しており、このチュートリアルでは各メソッドの使用法を説明します。
始める前に
魔法のメソッドを完全に理解するには、実際にそのメソッドが動作しているのを見るのが役立ちます。それでは、非常に単純なクラスの基本セットから始めましょう。ここでは、Device と Battery という 2 つのクラスを定義します。
プレーンコピーをクリップボードプリントに表示しますか?
クラスデバイス {
    パブリック $name;           // デバイスの名前
    パブリック $battery;        // Battery オブジェクトを保持します
    パブリック $data = array(); // その他を保存します。配列内のデータ
    パブリック $connection;     // 接続リソースを保持します
 
    保護された関数 connect() {
        // 外部ネットワークに接続します
        $this->connection = 'リソース'; 
        $this->name をエコーし​​ます。 「接続されました」。 PHP_EOL; 
    }
 
    保護された関数切断() {
        // ネットワークから安全に切断します
        $this->接続 = null; 
        $this->name をエコーし​​ます。 「切断されました」。 PHP_EOL; 
    }
}
 
クラス バッテリー {
    プライベート $charge = 0; 
 
    パブリック関数 setCharge($charge) {
        $charge = (int)$charge; 
        if($charge < 0) {
            $charge = 0; 
        }
        elseif($charge > 100) {
            $charge = 100; 
        }
        $this->charge = $charge; 
    }
}
?> 
「メソッド」や「プロパティ」などの言葉に馴染みがない場合は、まずこれについて読んでみるとよいでしょう。
デバイス オブジェクトは、名前、Battery オブジェクト、データの配列、および外部リソースへのハンドルを保持します。また、外部リソースに接続したり切断したりするためのメソッドもあります。 Battery オブジェクトは単に電荷をプライベート プロパティに保存し、電荷を設定するメソッドを備えています。
このチュートリアルは、オブジェクト指向プログラミングの基本を理解していることを前提としています。 「メソッド」や「プロパティ」などの言葉が馴染みのないものに聞こえる場合は、まずそれについて読んでみるとよいでしょう。
これらのクラスはまったく役に立ちませんが、各マジック メソッドの良い例になります。簡単なクラスを作成したので、魔法のメソッドを試してみましょう。
コンストラクターとデストラクター
コンストラクターとデストラクターは、それぞれオブジェクトの作成時と破棄時に呼び出されます。オブジェクトを保持する変数が設定解除または再割り当てされたか、スクリプトが実行を終了したため、オブジェクトへの参照がなくなると、オブジェクトは「破棄」されます。
__construct()
__construct() メソッドは、最も一般的に使用されるマジック メソッドです。ここで、オブジェクトの作成時に必要な初期化を行います。ここでは、オブジェクトの作成時に渡される引数をいくつでも定義できます。戻り値はすべて new キーワードを介して渡されます。コンストラクターで例外がスローされると、オブジェクトの作成が停止します。
プレーンコピーをクリップボードプリントに表示しますか?
クラスデバイス {
    //...
    public function __construct(Battery $battery, $name) {
        // $battery は有効な Battery オブジェクトのみになります
        $this->バッテリー = $バッテリー; 
        $this->name = $name; 
        // ネットワークに接続します
        $this->connect(); 
    }
    //...
}
コンストラクター メソッドを「private」と宣言すると、外部コードがオブジェクトを直接作成できなくなります。
ここでは、Battery と名前という 2 つの引数を受け入れるコンストラクターを宣言しました。コンストラクターは、オブジェクトが機能するために必要な各プロパティを割り当て、connect() メソッドを実行します。コンストラクターを使用すると、オブジェクトが存在する前に、オブジェクトに必要な要素がすべて揃っていることを確認できます。
ヒント: コンストラクター メソッドを「private」と宣言すると、外部コードがオブジェクトを直接作成できなくなります。これは、存在できるオブジェクトの数を制限するシングルトン クラスを作成する場合に便利です。
上記のコンストラクターを配置したら、「iMagic」というデバイスを作成する方法を次に示します:
プレーンコピーをクリップボードプリントに表示しますか?
$device = 新しいデバイス(新しいバッテリー(), 'iMagic'); 
// iMagic が接続されました
echo $device->name; 
// iMagic
ご覧のとおり、クラスに渡される引数は、実際にはコンストラクター メソッドに渡されます。また、connect メソッドが呼び出され、$name プロパティが設定されたこともわかります。
名前を渡すのを忘れたとします。何が起こるか:
プレーンコピーをクリップボードプリントに表示しますか?
$device = 新しいデバイス(新しいバッテリー()); 
// 結果: PHP 警告: Device::__construct() の引数 2 がありません
__destruct()
名前が示すように、オブジェクトが破棄されると __destruct() メソッドが呼び出されます。これは引数を受け入れず、通常、データベース接続を閉じるなどのクリーンアップ操作を実行するために使用されます。この例では、ネットワークから切断するために使用します。
プレーンコピーをクリップボードプリントに表示しますか?
クラスデバイス {
    //...
    パブリック関数 __destruct() {
        // ネットワークから切断します
        $this->disconnect(); 
        $this->name をエコーし​​ます。 ' 破壊されました' 。 PHP_EOL; 
    }
    //...
}
上記のデストラクターを配置すると、Device オブジェクトが破棄されると次のようになります:
プレーンコピーをクリップボードプリントに表示しますか?
$device = 新しいデバイス(新しいバッテリー(), 'iMagic'); 
// iMagic が接続されました
unset($device); 
// iMagic が切断されました
// iMagic が破壊されました
ここでは、unset() を使用してオブジェクトを破棄しました。破棄される前に、デストラクターは disconnect() メソッドを呼び出し、メッセージを出力します。メッセージはコメントで確認できます。
プロパティのオーバーロード
注: PHP の「オーバーロード」バージョンは、他のほとんどの言語とまったく同じではありませんが、同じ結果が得られます。
この次の一連のマジック メソッドは、プロパティ アクセスの処理に関するもので、存在しない (またはアクセスできない) プロパティにアクセスしようとしたときに何が起こるかを定義します。これらは疑似プロパティの作成に使用できます。これは、PHP ではオーバーロードと呼ばれます。
__get()
__get() メソッドは、アクセスできないプロパティにコードがアクセスしようとすると呼び出されます。プロパティの名前である 1 つの引数を受け入れます。プロパティの値として扱われる値を返す必要があります。 Device クラスの $data プロパティを覚えていますか?これらの「疑似プロパティ」をデータ配列の要素として保存し、クラスのユーザーが __get() 経由でそれらにアクセスできるようにします。それは次のようになります:
プレーンコピーをクリップボードプリントに表示しますか?
クラスデバイス {
    //...
    パブリック関数 __get($name) {
        // 指定されたキーが配列内に存在するかどうかを確認します
        if(array_key_exists($name, $this->data)) {
            // 次に、配列から値を返します
            $this->data[$name] を返します; 
        }
        null を返します。 
    }
    //...
}
__get() メソッドの一般的な使用法は、「読み取り専用」プロパティを作成してアクセス制御を拡張することです。たとえば、プライベート プロパティを持つ Battery クラスを考えてみましょう。プライベート $chargeproperty を外部コードから読み取ることはできますが、変更することはできません。コードは次のようになります:
プレーンコピーをクリップボードプリントに表示しますか?
クラス バッテリー {
    プライベート $charge = 0; 
 
    パブリック関数 __get($name) {
        if(isset($this->$name)) {
            $this->$name を返します。 
        }
        null を返します。 
    }
    //...
}
この例では、プロパティに動的にアクセスするために可変変数が使用されていることに注意してください。 $name の値が「user」であると仮定すると、$this->$name は $this->user に変換されます。 __set()
__set() メソッドは、コードがアクセスできないプロパティの値を変更しようとすると呼び出されます。プロパティの名前と値の 2 つの引数を受け入れます。 Device クラスの「疑似変数」配列は次のようになります:
プレーンコピーをクリップボードプリントに表示しますか?
クラスデバイス {
    //...
    パブリック関数 __set($name, $value) {
        // プロパティ名を配列キーとして使用します
        $this->data[$name] = $value; 
    }
    //...
}
__isset()
__isset() メソッドは、アクセスできないプロパティに対してコードが isset() を呼び出すときに呼び出されます。プロパティの名前である 1 つの引数を受け入れます。値の存在を表すブール値を返す必要があります。再び変数配列を使用すると、次のようになります:
プレーンコピーをクリップボードプリントに表示しますか?
クラスデバイス {
    //...
    パブリック関数 __isset($name) {
        // ここで isset() を使用することもできます
        return array_key_exists($name, $this->data); 
    }
    //...
}
__unset()
__unset() メソッドは、コードがアクセスできないプロパティを unset() しようとすると呼び出されます。プロパティの名前である 1 つの引数を受け入れます。私たちのものは次のようになります:
プレーンコピーをクリップボードプリントに表示しますか?
クラスデバイス {
    //...
    パブリック関数 __unset($name) {
        // unset() を配列要素に転送します
        unset($this->data[$name]); 
    }
    //...
}
プロパティのオーバーロードの動作
ここでは、私たちが宣言したプロパティ関連のマジック メソッドをすべて示します:
プレーンコピーをクリップボードプリントに表示しますか?
クラスデバイス {
    //...
    パブリック $data = array(); // その他を保存します。配列内のデータ
    //...
    パブリック関数 __get($name) {
        // 指定されたキーが配列内に存在するかどうかを確認します
        if(array_key_exists($name, $this->data)) {
            // 次に、配列から値を返します
            $this->data[$name] を返します; 
        }
        null を返します。 
    }
 
    パブリック関数 __set($name, $value) {
        // プロパティ名を配列キーとして使用します
        $this->data[$name] = $value; 
    }
 
    パブリック関数 __isset($name) {
        // ここで isset() を使用することもできます
        return array_key_exists($name, $this->data); 
    }
 
    パブリック関数 __unset($name) {
        // unset() を配列要素に転送します
        unset($this->data[$name]); 
    }
    //...
}
上記のマジック メソッドを使用して、name というプロパティにアクセスしようとすると、次のようになります。実際には $name プロパティが宣言されていないことに注意してください。ただし、内部クラス コードを見ないとそれはわかりません。
プレーンコピーをクリップボードプリントに表示しますか?
$device->user = 'スティーブ'; 
echo $device->user; 
// スティーブ
存在しないプロパティの値を設定し、正常に取得しました。さて、それはどこに保管されていますか?
プレーンコピーをクリップボードプリントに表示しますか?
print_r($device->data); 
/*
配列
(
    [ユーザー] =>スティーブ
)
*/
ご覧のとおり、$data プロパティには値を含む「name」要素が含まれています。
プレーンコピーをクリップボードプリントに表示しますか?
var_dump(isset($device->user)); 
// bool(true)
上記は、偽のプロパティに対して isset() を呼び出した結果です。
プレーンコピーをクリップボードプリントに表示しますか?
unset($device->user); 
var_dump(isset($device->user)); 
// bool(false)
上記は、偽のプロパティの設定を解除した結果です。念のため、ここに空のデータ配列を示します:
プレーンコピーをクリップボードプリントに表示しますか?
print_r($device->data); 
/*
配列
(
)
*/
オブジェクトをテキストとして表現する
場合によっては、オブジェクトを文字列表現に変換したい場合があります。単純にオブジェクトを印刷しようとすると、以下のようなエラーが発生します:
プレーンコピーをクリップボードプリントに表示しますか?
$device = 新しいデバイス(新しいバッテリー(), 'iMagic'); 
エコー $デバイス; 
// 結果 : PHP キャッチ可能な致命的なエラー: クラス Device のオブジェクトを文字列に変換できませんでした
__toString()
__toString() メソッドは、コードがオブジェクトを文字列のように処理しようとするときに呼び出されます。引数は受け入れられず、文字列を返す必要があります。これにより、オブジェクトがどのように表現されるかを定義できるようになります。この例では、簡単な概要を作成します:
プレーンコピーをクリップボードプリントに表示しますか?
クラスデバイス {
    ...
    パブリック関数 __toString() {
        // 接続されていますか? 
        $connected = (isset($this->connection)) ? '接続済み' : '切断されました'; 
        // どのくらいのデータがあるでしょうか? 
        $count = count($this->data); 
        // すべてをまとめてください
        $this->name を返します。 ' は ' 。 $接続済み 。 ' と ' 。 $count 。 「メモリ内のアイテム」。 PHP_EOL; 
    }
    ...
}
上記のメソッドが定義されているので、Device オブジェクトを印刷しようとすると次のようになります:
プレーンコピーをクリップボードプリントに表示しますか?
$device = 新しいデバイス(新しいバッテリー(), 'iMagic'); 
エコー $デバイス; 
// iMagic はメモリ内のアイテムが 0 個で接続されています
Device オブジェクトは、名前、ステータス、保存されているアイテムの数を含む短い概要で表されるようになりました。
__set_state() (PHP 5.1)
静的 __set_state() メソッド (PHP バージョン 5.1 以降で利用可能) は、オブジェクトに対して var_export() 関数が呼び出されたときに呼び出されます。 var_export() 関数は、変数を PHP コードに変換するために使用されます。このメソッドは、オブジェクトのプロパティ値を含む連想配列を受け入れます。簡単にするために、Battery クラスで使用してください。
プレーンコピーをクリップボードプリントに表示しますか?
クラス バッテリー {
    //...
    パブリック静的関数 __set_state(array $array) {
        $obj = 新しい self(); 
        $obj->setCharge($array['charge']); 
        $obj を返します。 
    }
    //...
}
このメソッドは単純に親クラスのインスタンスを作成し、渡された配列の値をチャージするように設定します。上記のメソッドが定義されているので、Device オブジェクトで var_export() を使用すると何が起こるかになります:
プレーンコピーをクリップボードプリントに表示しますか?
$device = 新しいデバイス(新しいバッテリー(), 'iMagic'); 
var_export($device->battery); 
/*
Battery::__set_state(array(
)    'チャージ' => 0、
))
*/
eval('$battery = ' . var_export($device->battery, true) . ';'); 
var_dump($battery); 
/*
オブジェクト(バッテリー)#3 (1) {
  ["料金:プライベート"]=>
  int(0)
}
*/
最初のコメントは、実際に何が起こっているかを示しています。つまり、var_export() が単に Battery::__set_state() を呼び出しているだけです。 2 番目のコメントは、バッテリーが正常に再作成されたことを示しています。
オブジェクトのクローン作成
デフォルトでは、オブジェクトは参照によって渡されます。したがって、他の変数をオブジェクトに代入しても、実際にはオブジェクトがコピーされるのではなく、同じオブジェクトへの新しい参照が作成されるだけです。オブジェクトを実際にコピーするには、clone キーワードを使用する必要があります。
この「参照渡し」ポリシーは、オブジェクト内のオブジェクトにも適用されます。オブジェクトのクローンを作成した場合でも、そのオブジェクトに含まれる子オブジェクトはクローンされません。したがって、同じ子オブジェクトを共有する 2 つのオブジェクトが作成されることになります。これを説明する例を次に示します:
プレーンコピーをクリップボードプリントに表示しますか?
$device = 新しいデバイス(新しいバッテリー(), 'iMagic'); 
$device2 = $device のクローンを作成します。 
 
$device->battery->setCharge(65); 
echo $device2->battery->charge; 
// 65
ここでは、Device オブジェクトのクローンを作成しました。すべての Device オブジェクトには Battery オブジェクトが含まれることに注意してください。デバイスの両方のクローンが同じバッテリーを共有していることを示すために、$device のバッテリーに加えた変更が $device2 のバッテリーに反映されます。
__クローン()
__clone() メソッドを使用すると、この問題を解決できます。クローン作成が行われた後、クローンされたオブジェクトのコピーに対して呼び出されます。ここで、子オブジェクトのクローンを作成できます。
プレーンコピーをクリップボードプリントに表示しますか?
クラスデバイス {
    ...
    パブリック関数 __clone() {
        // Battery オブジェクトをコピーします
        $this->battery = クローン $this->battery; 
    }
    ...
}
このメソッドを宣言すると、クローン化されたデバイスがそれぞれ独自のバッテリーを持っていることを確認できるようになります。
プレーンコピーをクリップボードプリントに表示しますか?
$device = 新しいデバイス(新しいバッテリー(), 'iMagic'); 
$device2 = $device のクローンを作成します。 
 
$device->battery->setCharge(65); 
echo $device2->battery->charge; 
// 0
一方のデバイスのバッテリーを変更しても、もう一方のデバイスには影響しません。
オブジェクトのシリアル化
シリアル化は、あらゆるデータを文字列形式に変換するプロセスです。これを使用して、オブジェクト全体をファイルまたはデータベースに保存できます。保存されたデータをシリアル化解除すると、元のオブジェクトが以前とまったく同じになります。ただし、シリアル化に関する 1 つの問題は、データベース接続など、すべてをシリアル化できるわけではないことです。幸いなことに、この問題を処理できる魔法の方法がいくつかあります。
__睡眠()
__sleep() メソッドは、オブジェクトに対して Serialize() 関数が呼び出されるときに呼び出されます。引数を受け入れず、シリアル化する必要があるすべてのプロパティの配列を返す必要があります。この方法で必要な保留中のタスクやクリーンアップを完了することもできます。
ヒント: __sleep() で破壊的な操作を行うことは避けてください。これはライブ オブジェクトに影響を与え、常に完了するとは限らないためです。
Device の例では、接続プロパティはシリアル化できない外部リソースを表します。したがって、私たちの __sleep() メソッドは、単に $connection を除くすべてのプロパティの配列を返します。
プレーンコピーをクリップボードプリントに表示しますか?
クラスデバイス {
    パブリック $name;           // デバイスの名前
    パブリック $battery;        // Battery オブジェクトを保持します
    パブリック $data = array(); // その他を保存します。配列内のデータ
    パブリック $connection;     // 接続リソースを保持します
    //...
    パブリック関数 __sleep() {
        // 保存するプロパティをリストします
        戻り配列('名前', 'バッテリー', 'データ'); 
    }
    //...
}
私たちの __sleep() は単に、保存する必要があるプロパティ名のリストを返します。
__ウェイクアップ()
__wakeup() メソッドは、格納されたオブジェクトに対して unserialize() 関数が呼び出されるときに呼び出されます。引数を受け入れず、何も返す必要はありません。これを使用して、シリアル化中に失われたデータベース接続またはリソースを再確立します。
Device の例では、connect() メソッドを呼び出して接続を再確立するだけです。
プレーンコピーをクリップボードプリントに表示しますか?
クラスデバイス {
    //...
    パブリック関数 __wakeup() {
        // ネットワークに再接続します
        $this->connect(); 
    }
    //...
}
メソッドのオーバーロード
これらの最後の 2 つのメソッドは、メソッドを処理するためのものです。これはプロパティのオーバーロード メソッド (__get()、__set() など) と同じ概念ですが、メソッドに適用されます。
__call()
__call() は、コードがアクセスできないメソッドまたは存在しないメソッドを呼び出そうとしたときに呼び出されます。これは、呼び出されるメソッドの名前と引数の配列という 2 つの引数を受け入れます。たとえば、この情報を使用して、子オブジェクトで同じメソッドを呼び出すことができます。
例では、call_user_func_array() 関数が使用されていることに注意してください。この関数を使用すると、配列に格納された引数を使用して名前付き関数 (またはメソッド) を動的に呼び出すことができます。最初の引数は、呼び出す関数を指定します。メソッドに名前を付ける場合、最初の引数はクラス名またはオブジェクト インスタンスとプロパティの名前を含む配列です。 2 番目の引数は常に、渡す引数のインデックス付き配列です。
この例では、メソッド呼び出しを $connection プロパティ (オブジェクトであると仮定します) に渡します。その結果を呼び出し元のコードに直接返します。
プレーンコピーをクリップボードプリントに表示しますか?
クラスデバイス {
    //...
    public function __call($name, $arguments) {
        // 子オブジェクトにこのメソッドがあることを確認してください
        if(method_exists($this->connection, $name)) {
            // 呼び出しを子オブジェクトに転送します
            return call_user_func_array(array($this->connection, $name), $arguments); 
        }
        null を返します。 
    }
    //...
}
iDontExist() メソッドを呼び出そうとすると、上記のメソッドが呼び出されます:
プレーンコピーをクリップボードプリントに表示しますか?
$device = 新しいデバイス(新しいバッテリー(), 'iMagic'); 
$device->iDontExist(); 
// __call() はこれを $device->connection->iDontExist() に転送します
__callStatic() (PHP 5.3)
__callStatic() (PHP バージョン 5.3 以降で利用可能) は、コードが静的コンテキストでアクセスできないメソッドまたは存在しないメソッドを呼び出そうとするときに呼び出される点を除いて、__call() と同じです。
この例の唯一の違いは、メソッドを静的として宣言し、オブジェクトではなくクラス名を参照していることです。
プレーンコピーをクリップボードプリントに表示しますか?
クラスデバイス {
    //...
    パブリック静的関数 __callStatic($name, $arguments) {
        // クラスにこのメソッドがあることを確認してください
        if(method_exists('接続', $name)) {
            // 静的呼び出しをクラスに転送します
            return call_user_func_array(array('Connection', $name), $arguments); 
        }
        null を返します。 
    }
    //...
}
静的 iDontExist() メソッドを呼び出そうとすると、上記のメソッドが呼び出されます:
プレーンコピーをクリップボードプリントに表示しますか?
デバイス::iDontExist(); 
// __callStatic() はこれを Connection::iDontExist() に転送します
オブジェクトを関数として使用する
オブジェクトを関数として使用したい場合があります。オブジェクトを関数として使用できるため、他の言語と同様に関数を引数として渡すことができます。
__invoke() (PHP 5.3)
__invoke() (PHP バージョン 5.3 以降で利用可能) は、コードがオブジェクトを関数として使用しようとすると呼び出されます。このメソッドで定義された引数はすべて関数の引数として使用されます。この例では、受け取った引数を単純に出力します。
プレーンコピーをクリップボードプリントに表示しますか?
クラスデバイス {
    //...
    パブリック関数 __invoke($data) {
        $data をエコーし​​ます。 
    }
    //...
}
上記の定義により、Device を関数として使用すると次のようになります:
プレーンコピーをクリップボードプリントに表示しますか?
$device = 新しいデバイス(新しいバッテリー(), 'iMagic'); 
$device('テスト'); 
// $device->__invoke('test') に相当します
// 出力: テスト
ボーナス: __autoload()
これは魔法の方法ではありませんが、それでも非常に便利です。存在しないクラスが参照されると、__autoload() 関数が自動的に呼び出されます。これは、スクリプトが失敗する前に、クラス宣言を含むファイルをロードする最後のチャンスを与えることを目的としています。必要な場合に備えて、常にすべてのクラスをロードする必要はないため、これは便利です。
この関数は 1 つの引数、つまり参照されるクラスの名前を受け入れます。 「inc」ディレクトリ内の「classname.class.php」という名前のファイルに各クラスがあるとします。自動ロードは次のようになります:
プレーンコピーをクリップボードプリントに表示しますか?
関数 __autoload($class_name) {
    $class_name = strto lower($class_name); 
    include_once './inc/' 。 $class_name 。 '.class.php'; 
}
結論
マジック メソッドは非常に便利で、柔軟なアプリケーション フレームワークを開発するための強力なツールを提供します。これらは、PHP オブジェクトを他のオブジェクト指向言語のオブジェクトに近づけ、より便利な機能の一部を再現できるようにします。ここでマジックメソッドに関する PHP マニュアルページを読むことができます。このチュートリアルがお役に立ち、概念を明確に説明できたことを願っています。ご質問がある場合は、コメント欄でお気軽にお問い合わせください。読んでいただきありがとうございます。

www.bkjia.comtru​​ehttp://www.bkjia.com/PHPjc/477991.html技術記事 PHP には、オブジェクト指向プログラミングで非常に巧妙なトリックを実行できるマジック メソッドが多数用意されています。これらのメソッドは、2 つのアンダースコア接頭辞 (__) で識別され、機能します...
関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート