目次前のトピック次のトピックこのページ |
クラスとオブジェクト¶Zephirはオブジェクト指向プログラミングを促進します。これが拡張内のメソッドとクラスだけがエクスポートできる理由です。また、ほとんどの場合においてfatal error あるいは warningではなく実行時エラーが例外を上げるでしょう。 クラス¶各Zephirファイルは(ちょうど1つの)クラスあるいはインタフェースを実装する必要があります。クラスの構造はPHPクラスにとてもよく似ています: namespace Test;
/**
* これはサンプルクラスです
*/
class MyClass
{
}
クラス修飾子¶以下のクラス修飾子がサポートされます: Final: もしクラスがこの修飾子を持つ場合、継承できません。 namespace Test;
/**
* このクラスは他のクラスによって継承することができません
*/
final class MyClass
{
}
Abstract: もしクラスがこの修飾子を持つ場合、インスタンス化できません。 namespace Test;
/**
* このクラスはインスタンス化することができません
*/
abstract class MyClass
{
}
実装メソッド¶“function” キーワードはメソッドを導入します。メソッドはPHPで利用可能な通常の可視修飾子を実装します。Zephirでは可視修飾子の明示的な設定が必須です。 namespace Test;
class MyClass
{
public function myPublicMethod()
{
// ...
}
protected function myProtectedMethod()
{
// ...
}
private function myPrivateMethod()
{
// ...
}
}
メソッドは必須および任意のパラメータを受け取ることができます: namespace Test;
class MyClass
{
/**
* 全てのパラメータが必須です
*/
public function doSum1(a, b)
{
return a + b;
}
/**
* 'a' だけが必須で、'b' は任意でデフォルトの値を持ちます
*/
public function doSum2(a, b = 3)
{
return a + b;
}
/**
* 両方のパラメータが任意です
*/
public function doSum3(a = 1, b = 2)
{
return a + b;
}
/**
* パラメータが必須でそれらの値はintegerでなければなりません
*/
public function doSum4(int a, int b)
{
return a + b;
}
/**
* デフォルトの値を持つ静的な型
*/
public function doSum4(int a = 4, int b = 2)
{
return a + b;
}
}
任意の nullable パラメータ¶Zephirは変数の値が変数が宣言された時の型を保持することを保証します。変数がnull値を持つ時コンパイラが行うこの保証はZephirにnull値を最も適切な値に変換させます: public function foo(int a = null)
{
echo a; // "a" が渡されない場合、0を出力します
}
public function foo(boolean a = null)
{
echo a; // "a" が渡されない場合、falseを出力します
}
public function foo(string a = null)
{
echo a; // "a" が渡されない場合、空の文字列を出力します
}
public function foo(array a = null)
{
var_dump(a); // "a" が渡されない場合、空の配列を出力します
}
サポートされる可視性¶
サポートされる修飾子¶
Getter/Setter のショートカット¶C#のように、Zephir内でget/set/toString ショートカットを使うことができます。この機能により明示的なそれらのメソッドの実装無しにプロパティに対してsetterおよびgetterを簡単に書くことができます。 例えば、ショートカット無しではコードは以下のようになるかも知れません: namespace Test;
class MyClass
{
protected myProperty;
protected someProperty = 10;
public function setMyProperty(myProperty)
{
let this->myProperty = myProperty;
}
public function getMyProperty()
{
return this->myProperty;
}
public function setSomeProperty(someProperty)
{
let this->someProperty = someProperty;
}
public function getSomeProperty()
{
return this->someProperty;
}
public function __toString()
{
return this->myProperty;
}
}
同じコードを以下のようにショートカットを使って書くことができます: namespace App;
class MyClass
{
protected myProperty {
set, get, toString
};
protected someProperty = 10 {
set, get
};
}
コードがコンパイルされる時に、それらのメソッドは実際のメソッドとしてエクスポートされますが、それらを一つ一つ書く必要はありません。 返り値の型ヒント¶クラスおよびインタフェース内のメソッドは “return type hints” を持つことができます; これらはアプリケーション内でエラーについて知らせる便利で特別な情報をコンパイラに提供するでしょう。次の例を考えます: namespace App;
class MyClass
{
public function getSomeData() -> string
{
// これはコンパイラ例外を投げるでしょう
// 返り値(boolean)が一致しないため
// 期待される返り値の型の文字列
return false;
}
public function getSomeOther() -> <App\MyInterface>
{
// これはコンパイラ例外を投げるでしょう
// もし返り値のオブジェクトが実装されていない場合
// 期待されるインタフェース App\MyInterface
return new App\MyObject;
}
public function process()
{
var myObject;
// type-hint はコンパイラに次のことを伝えます
// myObject はクラスのインスタンスで
// App\MyInterface を実装します
let myObject = this->getSomeOther();
// コンパイラは App\MyInterface が以下であるかをチェックするでしょう
// "someMethod" という名のメソッドが実装されているかどうか
echo myObject->someMethod();
}
}
メソッドは1つ以上の返り値の型をもつことができます。複数の型が定義された場合、オペレータ | がそれらの型を分割するために使われるべきです。 namespace App;
class MyClass
{
public function getSomeData(a) -> string | bool
{
if a == false {
return false;
}
return "error";
}
}
返り値の型: Void¶メソッドは ‘void’ としてマークすることもできます。このことはメソッドがどのようなデータも返すことができないことを意味します: public function setConnection(connection) -> void
{
let this->_connection = connection;
}
なぜこれが便利なのか?プログラムがこれらのメソッドからの返り値を期待していて、プログラムがコンパイル例外を生成するかどうかをコンパイラが検知できるからです。 let myDb = db->setConnection(connection);
myDb->execute("SELECT * FROM robots"); // これは例外を生成するでしょう
Strict/Flexible パラメータのデータ型¶Zephirでは、メソッドの各パラメータのデータ型を指定することができます。デフォルトでは、これらのデータ型は柔軟です。このことはもし間違った(でも互換性がある)データ型の値が渡された場合、Zephirは透過的にそれを期待しているものに変換しようとすることを意味します。 public function filterText(string text, boolean escape=false)
{
//...
}
上のメソッドは以下の呼び出しで動作するでしょう:
$o->filterText(1111, 1); // OK
$o->filterText("some text", null); // OK
$o->filterText(null, true); // OK
$o->filterText("some text", true); // OK
$o->filterText(array(1, 2, 3), true); // FAIL
しかし、間違った型を渡すことはしばしばバグに繋がります。あるAPIの間違った使い方は期待しない結果を生成するかも知れません。厳密なデータ型を持つパラメータを設定することで、自動的な変換を却下することができます: public function filterText(string! text, boolean escape=false)
{
//...
}
これで、間違った型を持つほとんどの呼び出しは無効なデータ型が渡されたことによる例外を引き起こすでしょう:
$o->filterText(1111, 1); // FAIL
$o->filterText("some text", null); // OK
$o->filterText(null, true); // FAIL
$o->filterText("some text", true); // OK
$o->filterText(array(1, 2, 3), true); // FAIL
どのパラメータが厳密でどれが柔軟でなければならないかを指定することで、開発者は彼/彼女が期待する特定の挙動を設定することができます。 Read-Only パラメータ¶キーワード ‘const’ を使うと、パラメータを read-only としてマークすることができ、これは const-correctness を留意することに役立ちます。この属性でマークされたパラメータはメソッド内で変更することができません: namespace App;
class MyClass
{
// "a" は read-only
public function getSomeData(const string a)
{
// これはコンパイル例外を投げるでしょう
let a = "hello";
}
}
パラメータがread-onlyとして宣言されると、コンパイラはこれらの変数に対して安全という仮定をすることができ、更に最適化を行うことができます。 プロパティの実装¶クラスメンバー変数は “properties” と呼ばれます。デフォルトでは、それらはPHPのプロパティとして振舞います。プロパティはPHP拡張にエクスポートされ、PHPコードから見えます。プロパティはPHPで利用可能な通常の可視修飾子を実装し、Zephir内では明示的な可視修飾子の設定が必須です: namespace Test;
class MyClass
{
public myProperty1;
protected myProperty2;
private myProperty3;
}
クラスメソッド内で非staticプロパティは using -> (Object Operator) を使ってアクセスされるかも知れません: this->property (propartyはプロパティの名前です): namespace Test;
class MyClass
{
protected myProperty;
public function setMyProperty(var myProperty)
{
let this->myProperty = myProperty;
}
public function getMyProperty()
{
return this->myProperty;
}
}
プロパティは文字互換のデフォルト値を持つことができます。これらの値はコンパイル時に評価可能でなければならず、評価されるために実行時の情報に非依存でなければなりません: namespace Test;
class MyClass
{
protected myProperty1 = null;
protected myProperty2 = false;
protected myProperty3 = 2.0;
protected myProperty4 = 5;
protected myProperty5 = "my value";
}
プロパティの更新¶プロパティは the ‘->’ operator を使ってそれらにアクセスすることで更新することができます: let this->myProperty = 100;
Zephirはプログラムがプロパティにアクセスする時にそれらをチェックします。もしプロパティが宣言されていない場合は、コンパイル例外を取得するでしょう: CompilerException: Property '_optionsx' is not defined on class 'App\MyClass' in /Users/scott/utils/app/myclass.zep on line 62
let this->_optionsx = options;
------------^
このコンパイラ検証を避けるか動的にプロパティを作成したいだけの場合は、文字列クォートを使ってプロパティ名を囲むことができます: let this->{"myProperty"} = 100;
プロパティを更新するために単純な変数を使うこともできます。プロパティ名は変数から取り出されるでしょう: let someProperty = "myProperty";
let this->{someProperty} = 100;
プロパティの読み込み¶プロパティは the ‘->’ operator を使ってそれらにアクセスすることで読み込むことができます: echo this->myProperty;
更新する時にプロパティは動的に以下の方法を使って読み込むことができます: //コンパイラチェックを避けるか動的なユーザ定義のプロパティを読み込む
echo this->{"myProperty"};
//変数名を使って読み込む
let someProperty = "myProperty";
echo this->{someProperty}
クラス定数¶クラスは一度拡張がコンパイルされると、同じであり続け、変更できないクラス定数を含むことができます。クラス定数はPHPから使うことができるPHP拡張にエクスポートされます namespace Test;
class MyClass
{
const MYCONSTANT1 = false;
const MYCONSTANT2 = 1.0;
}
クラス定数はクラス名とstatic演算子 (::) を使ってアクセスすることができます: namespace Test;
class MyClass
{
const MYCONSTANT1 = false;
const MYCONSTANT2 = 1.0;
public function someMethod()
{
return MyClass::MYCONSTANT1;
}
}
メソッドの呼び出し¶メソッドはPHPのようにオブジェクト演算子 (->) を使って呼ぶことができます: namespace Test;
class MyClass
{
protected function _someHiddenMethod(a, b)
{
return a - b;
}
public function someMethod(c, d)
{
return this->_someHiddenMethod(c, d);
}
}
Staticメソッドはstatic演算子 (::) を使って呼ばれなければなりません: namespace Test;
class MyClass
{
protected static function _someHiddenMethod(a, b)
{
return a - b;
}
public static function someMethod(c, d)
{
return self::_someHiddenMethod(c, d);
}
}
以下のように動的なやり方でメソッドを呼ぶことができます: namespace Test;
class MyClass
{
protected adapter;
public function setAdapter(var adapter)
{
let this->adapter = adapter;
}
public function someMethod(var methodName)
{
return this->adapter->{methodName}();
}
}
名前によるパラメータ¶Zephir は名前あるいはキーワード引数によるメソッドパラメータの呼び出しをサポートします。任意の順番でパラメータを渡す、パラメータの意味を説明する、あるいはもっと優雅な方法でパラメータを指定したい場合に名前付きのパラメータは便利かも知れません。 “Image” と呼ばれるクラスが4つのパラメータを受け取る以下の例を考えます: namespace Test;
class Image
{
public function chop(width = 600, height = 400, x = 0, y = 0)
{
//...
}
}
メソッド呼び出しの通常の方法を使う場合: i->chop(100); // width=100, height=400, x=0, y=0
i->chop(100, 50, 10, 20); // width=100, height=50, x=10, y=20
名前付きのパラメータを使う場合: i->chop(width: 100); // width=100, height=400, x=0, y=0
i->chop(height: 200); // width=600, height=200, x=0, y=0
i->chop(height: 200, width: 100); // width=100, height=200, x=0, y=0
i->chop(x: 20, y: 30); // width=600, height=400, x=20, y=30
(コンパイル時に)コンパイラがこれらのパラメータの正しい順番を知らない場合、それらは実行時に解決されます。この場合、最小限の追加の余計なオーバーヘッドがあるかも知れません: let i = new {someClass}();
i->chop(y:30, x: 20);
|