クラスの概要
このページでは、InterSystems IRIS® データ・プラットフォームのクラスについて説明し、これらのクラスに Python または ObjectScript で記述されたメソッドを含める方法を示します。クラス定義は、正式にはどちらの言語の一部でもありません。クラスの定義に使用される構文は、クラス定義言語と呼ばれます。
他のメソッド実装言語も、主に移行目的でサポートされています。
クラス名とパッケージ
各 InterSystems IRIS. クラスは名前を持ち、その名前は、それが定義されているネームスペース内で一意である必要があります。完全なクラス名は、例えば、package.subpackage.subpackage.class のような、1 つ以上のピリオドで区切られた文字列です。短いクラス名は、この文字列内の最後のピリオドの後の部分であり、最後のピリオドの前の部分はパッケージ名です。
パッケージ名は単なる文字列ですが、ピリオドが含まれている場合、InterSystems IRIS 開発ツールは、ピリオドで区切られた各部分をサブパッケージとして処理します。統合開発環境 (IDE) およびその他のツールでは、便宜上、これらのサブパッケージはフォルダの階層として表示されます。
クラス定義の基本的なコンテンツ
InterSystems IRIS クラスの定義には、以下の項目を含めることができ、これらはすべてクラス・メンバと呼ばれます。
-
パラメータ — パラメータは、このクラスによって使用される定数値を定義します。この値はコンパイル時に設定されます。
-
プロパティ — プロパティには、クラスのインスタンスのデータが格納されます。
-
メソッド — インスタンス・メソッドとクラス・メソッド (他の言語では静的メソッドと呼ぶ) の 2 種類のメソッドがあります。
-
クラス・クエリ — クラス・クエリは、クラスが使用できる SQL クエリを定義し、クエリのためのコンテナとして使用するクラスを指定します。"クラス・クエリの定義と使用" を参照してください。
-
XData ブロック — XData ブロックは、クラスによって使用されるデータのユニット (XML、JSON、または YAML) です。"XData ブロックの定義と使用" を参照してください。
-
その他の種類のクラス・メンバ (永続クラスにのみ関連するメンバ)。
クラス定義には、キーワードを含めることができ、それらはクラス・コンパイラ動作に作用します。キーワードには、クラス全体に対して指定できるものと、特定のクラス・メンバに対して定義できるものがあります。これらのキーワードは、クラス・コンパイラが生成するコードに作用し、その結果、クラスの動作を制御します。
以下に、ObjectScript および Python で記述された簡単なクラス定義とメソッドを示します。
Class MyApp.Main.SampleClass Extends %RegisteredObject
{
Parameter CONSTANTMESSAGE [Internal] = "Hello world!" ;
Property VariableMessage As %String [ InitialExpression = "How are you?"];
Property MessageCount As %Numeric [Required];
ClassMethod HelloWorld() As %String [ Language = objectscript ]
{
Set x=..#CONSTANTMESSAGE
Return x
}
Method WriteIt() [ Language = objectscript, ServerOnly = 1]
{
Set count=..MessageCount
For i=1:1:count {
Write !,..#CONSTANTMESSAGE," ",..VariableMessage
}
}
}
Class MyApp.Main.SampleClass Extends %RegisteredObject
{
Parameter CONSTANTMESSAGE [Internal] = "Hello world!" ;
Property VariableMessage As %String [ InitialExpression = "How are you?"];
Property MessageCount As %Numeric [Required];
ClassMethod HelloWorld() As %String [ Language = python ]
{
import iris
x = iris.MyApp.Main.SampleClass._GetParameter("CONSTANTMESSAGE")
return x
}
Method WriteIt() [ ServerOnly = 1, Language = python ]
{
import iris
count = self.MessageCount
print()
for i in range(count):
print(iris.cls(__name__)._GetParameter("CONSTANTMESSAGE"), self.VariableMessage)
}
}
以下の点に注意してください。
-
最初の行は、クラスの名前を指定します。MyApp.Main.SampleClass は完全なクラス名であり、MyApp.Main がパッケージ名、SampleClass が短いクラス名です。
IDE および他のユーザ・インタフェースでは、各パッケージはフォルダとして処理されます。
-
Extends はコンパイラ・キーワードです。
Extends キーワードは、このクラスが %RegisteredObjectOpens in a new tab のサブクラスであることを指定します。これは、オブジェクトをサポートするために用意されているシステム・クラスです。このサンプルのクラスでは 1 つのクラスのみを拡張していますが、他の複数のクラスを拡張することもできます。また、それらのクラスが他のクラスを拡張することもできます。
-
CONSTANTMESSAGE はパラメータです。慣例で、InterSystems IRIS システム・クラスのすべてのパラメータの名前はすべて大文字にします。これは、便利な慣例ですが、これに従う必要はありません。
Internal キーワードはコンパイラ・キーワードです。これは、このパラメータが内部であることを示し、クラス・ドキュメントで表示されないようにします。このパラメータは文字列値を持ちます。
Python でクラス・パラメータにアクセスするには、組み込みメソッド %GetParameter() を使用してパラメータの値を返します。ただし、Python では、識別子名にパーセント記号文字を使用できないため、代わりにアンダースコアで置き換える必要があります。
-
ObjectScript で現在のクラスを参照するには、ドット (.) を使用します。
-
Python で現在のクラスを参照するには、コンテキストに応じて self、iris.Package.Class、または iris.cls(__name__) を使用できます。例では、3 つの構文形式すべてを示しています。iris.cls(__name__) は、2 つのアンダースコアが name の前と後にあります。(詳細は、"他のクラス・メンバの参照" を参照してください。)
-
VariableMessage および MessageCount はプロパティです。As の後の項目は、これらのプロパティのタイプを示します。InitialExpression および Required はコンパイラ・キーワードです。
例で示しているように、InterSystems IRIS クラス・プロパティに ObjectScript または Python から直接アクセスできます。
-
HelloWorld() はクラス・メソッドであり、文字列を返します。これは As の後の項目によって示されます。
このメソッドは、クラス・パラメータの値を使用します。
-
WriteIt() はインスタンス・メソッドであり、値を返しません。
このメソッドは、クラス・パラメータの値と 2 つのプロパティの値を使用します。
ServerOnly コンパイラ・キーワードは、このメソッドが外部クライアントに投影されないことを意味します。
以下のターミナル・セッションは、このクラスの使用法を示しています。どちらのターミナル・シェルも、クラスの ObjectScript バージョンと Python バージョンで有効です。
TESTNAMESPACE>write ##class(MyApp.Main.SampleClass).HelloWorld()
Hello world!
TESTNAMESPACE>set x = ##class(MyApp.Main.SampleClass).%New()
TESTNAMESPACE>set x.MessageCount=3
TESTNAMESPACE>do x.WriteIt()
Hello world! How are you?
Hello world! How are you?
Hello world! How are you?
>>> print(iris.MyApp.Main.SampleClass.HelloWorld())
Hello world!
>>> x = iris.MyApp.Main.SampleClass._New()
>>> x.MessageCount=3
>>> x.WriteIt()
Hello world! How are you?
Hello world! How are you?
Hello world! How are you?
InterSystems IRIS 2024.2 より、組み込み Python から InterSystems IRIS クラスを参照するための、オプションの短い構文が導入されました。新しいフォームも従来のフォームもどちらも使用できます。
クラス・パラメータ
クラス・パラメータは、指定されたクラスのすべてのオブジェクトに対して同じ値を定義します。まれに例外がありますが、この値は、クラスのコンパイル時に確立され、実行時に変更することはできません。クラス・パラメータは、以下の目的で使用します。
-
実行時に変更できない値を定義するため。
-
クラス定義に関するユーザ指定の情報を定義するため。クラス・パラメータは、単純な任意の名前と値の組み合わせです。この組み合わせを使用して、クラスに関する必要な情報を保存します。
-
プロパティとして使用する場合、さまざまなデータ型クラスの動作をカスタマイズするため (検証情報の提供など)。これについては、次のセクションで説明します。
-
使用するメソッド・ジェネレータ・メソッドに対して、パラメータ化された値を提供するため。
ObjectScript メソッド、Python メソッド、またはこれら 2 つの組み合わせが含まれる InterSystems IRIS クラスのパラメータを定義できます。以下に、いくつかのパラメータを持つクラスを示します。
Class GSOP.DivideWS Extends %SOAP.WebService
{
Parameter USECLASSNAMESPACES = 1;
/// Name of the Web service.
Parameter SERVICENAME = "Divide";
/// SOAP namespace for the Web service
Parameter NAMESPACE = "http://www.mynamespace.org";
/// let this Web service understand only SOAP 1.2
Parameter SOAPVERSION = "1.2";
///further details omitted
}
プロパティ
オブジェクト・クラスは、プロパティを持つことができます。InterSystems IRIS には、以下の 2 種類のプロパティがあります。
-
属性 - 値を保持します。この値は、以下のいずれかです。
-
1 つのリテラル値。通常、データ型に基づきます。
-
オブジェクト値 (コレクション・オブジェクトとストリーム・オブジェクトがあります)。
-
多次元配列。これはあまり一般的ではありません。
プロパティという用語は、関連付けを保持するプロパティではなく、単に、属性のプロパティを示すことがよくあります。
-
-
リレーションシップ - オブジェクト間の関連付けを保持します。
ObjectScript メソッド、Python メソッド、またはこれら 2 つの組み合わせが含まれるクラスのプロパティを定義できます。ただし、Python メソッドからリレーションシップにアクセスすることはできません。このセクションでは、これらのバリエーションのいくつかを示すプロパティ定義を含むサンプル・クラスを示します。
Class MyApp.Main.Patient Extends %Persistent
{
Property PatientID As %String [Required];
Property Gender As %String(DISPLAYLIST = ",Female,Male", VALUELIST = ",F,M");
Property BirthDate As %Date;
Property Age As %Numeric [Transient];
Property MyTempArray [MultiDimensional];
Property PrimaryCarePhysician As Doctor;
Property Allergies As list Of PatientAllergy;
Relationship Diagnoses As PatientDiagnosis [ Cardinality = children, Inverse = Patient ];
}
以下に留意してください。
-
それぞれの定義では、As の後の項目はプロパティのタイプです。各タイプはクラスです。構文 As List Of は、特定のコレクション・クラスの省略表現です。
%StringOpens in a new tab、%DateOpens in a new tab、および %NumericOpens in a new tab はデータ型クラスです。
%StringOpens in a new tab は既定のタイプです。
-
Diagnoses は、リレーションシップ・プロパティであり、残りは属性プロパティです。
-
PatientID、Gender、BirthDate、および Age は、単純なリテラル値のみを格納できます。
-
PatientID は Required キーワードを使用するため、必須です。つまり、このクラスのオブジェクトは、このプロパティの値を指定しない場合、保存できません。
-
Age は、他のリテラル・プロパティとは異なり、ディスクに保存されません。これは、それが Transient キーワードを使用するためです。
-
MyTempArray は MultiDimensional キーワードを使用するため、多次元プロパティです。このプロパティは既定では、ディスクに保存されません。
-
PrimaryCarePhysician および Allergies は、オブジェクト値プロパティ です。
-
Gender プロパティ定義には、プロパティ・パラメータの値が含まれます。これらは、このプロパティが使用するデータ型クラスのパラメータです。
このプロパティの値は、M と F に制限されます。表示値を表示すると (管理ポータルなどで)、代わりに Male と Female が表示されます。各データ型クラスでは、LogicalToDisplay() などのメソッドが提供されます。
メソッド
インスタンス・メソッドとクラス・メソッド (他の言語では静的メソッドと呼ぶ) の 2 種類のメソッドがあります。インスタンス・メソッドは、オブジェクト・クラスでのみ使用できます。
InterSystems IRIS では、メソッドを ObjectScript または Python で記述できます。メソッドの記述に使用する言語を指定するには、以下の構文を使用します。
Method MyMethod() [ Language = objectscript ]
{
// implementation details written in ObjectScript
}
Method MyMethod() [ Language = python ]
{
# implementation details written in Python
}
メソッドで Language キーワードを使用しない場合、コンパイラはメソッドがクラスの既定言語で記述されていると想定します。
前述の例のように、メソッドの言語はすべて小文字で記述する必要があります。
他のクラス・メンバの参照
メソッド内で、ここに示す構文を使用し、他のクラスのメンバを参照します。
-
パラメータを参照するには、以下のような式を使用します。
..#PARAMETERNAME
# technique 1 iris.Package.Class._GetParameter("PARAMETERNAME") # technique 2 objectinstance._GetParameter("PARAMETERNAME")
インターシステムズが提供するクラスでは、慣例ですべてのパラメータがすべて大文字で定義されていますが、作成するコードでは大文字にしなくてもかまいません。
-
別のインスタンス・メソッドを参照するには、以下のような式を使用します。
..methodname(arguments)
self.methodname(arguments)
この構文をクラス・メソッド内で使用して、インスタンス・メソッドを参照することはできません。
-
別のクラス・メソッドを参照するには、以下の構文を使用します。
..classmethodname(arguments)
# technique 1 iris.Package.Class.classmethodname(arguments) # technique 2 iris.cls(__name__).classmethodname(arguments)
Python の self 構文を使用してクラス・メソッドにアクセスすることはできません。代わりに、__name__ プロパティを使用して、前述の例に示すように現在のクラスの名前を取得できます。
-
(インスタンス・メソッド内のみ) インスタンスのプロパティを参照するには、以下のような式を使用します。
..PropertyName
self.PropertyName
同様に、オブジェクト値プロパティのプロパティを参照するには、以下のような式を使用します。
..PropertyNameA.PropertyNameB
self.PropertyNameA.PropertyNameB
ObjectScript の例で使用されている構文は、ドット構文と呼ばれます。
また、オブジェクト値プロパティのインスタンス・メソッドまたはクラス・メソッドを呼び出すこともできます。以下に例を示します。
Do ..PropertyName.MyMethod()
self.PropertyName.MyMethod()
他のクラスのメソッドの参照
メソッド内で (またはルーチン内で)、ここに示す構文を使用し、他のクラスのメソッドを参照します。
-
クラス・メソッドを呼び出し、その返り値にアクセスするには、以下のような式を使用します。
##class(Package.Class).MethodName(arguments)
iris.Package.Class.MethodName(arguments)
以下に例を示します。
set x = ##class(Util.Utils).GetToday()
x = iris.Util.Utils.GetToday()
以下のように、戻り値にアクセスせずにクラス・メソッドを呼び出すこともできます。
do ##class(Util.Utils).DumpValues()
iris.Util.Utils.DumpValues()
Note:##class は、大文字と小文字を区別しません。
-
インスタンス・メソッドを呼び出すには、インスタンスを作成し、ObjectScript または Python で以下のような式を使用してそのメソッドを呼び出し、その戻り値にアクセスします。
instance.MethodName(arguments)
以下に例を示します。
Set x=instance.GetName()
x=instance.GetName()
以下のように呼び出すことで、戻り値にアクセスせずにインスタンス・メソッドを呼び出すこともできます。
Do instance.InsertItem("abc")
instance.InsertItem("abc")
返り値がないメソッドもあるので、自身の状況にあった構文を選択してください。
現在のインスタンスの参照
場合によっては、インスタンス・メソッド内で、そのインスタンスのプロパティまたはメソッドではなく、現在のインスタンス自体を参照することが必要になります。例えば、他のコードを呼び出すときに、現在のインスタンスを渡すことが必要な場合があります。
ObjectScript では、特殊変数 $THIS を使用して現在のインスタンスを参照します。Python では、変数 self を使用して現在のインスタンスを参照します。
以下に例を示します。
Set sc=header.ProcessService($this)
sc=header.ProcessService(self)
メソッド引数
メソッドは、コンマ区切りリストで位置を示す引数を取ります。引数ごとに、型および既定の値を指定できます。
例えば、以下は、3 つの引数を取るメソッドの定義の一部分です。これは、InterSystems IRIS クラス内の ObjectScript メソッドと Python メソッドの両方で有効な構文です。
Method Calculate(count As %Integer, name, state As %String = "CA") as %Numeric
{
// ...
}
引数のうち 2 つが明示的な型を持ち、1 つが既定の値を持っています。一般的に、各引数の型を明示的に指定することは良い方法です。
メソッドが Python で定義されていて、そのメソッドの引数に既定値が指定されている場合、その引数を引数リストの末尾に配置して、コンパイル・エラーを避ける必要があります。
引数のスキップ
メソッドに適切な既定値がある場合、メソッドを呼び出すときに引数をスキップできます。ObjectScript と Python にはそれぞれ、引数をスキップするための独自の構文があります。
ObjectScript で引数をスキップするには、引数の値を指定せずにコンマ構造を維持します。例えば、以下は有効です。
set myval=##class(mypackage.myclass).GetValue(,,,,,,4)
InterSystems IRIS クラスでは、Python メソッドのシグニチャで最初に必須の引数を記述し、その後に引数と既定値を記述する必要があります。
そのメソッドを呼び出す際に、引数をメソッドのシグニチャの順番で指定する必要があります。したがって、1 つの引数をスキップした場合、その後の引数もすべてスキップする必要があります。例えば、以下は有効です。
ClassMethod Skip(a1, a2 As %Integer = 2, a3 As %Integer = 3) [ Language = python ]
{
print(a1, a2, a3)
}
TESTNAMESPACE>do ##class(mypackage.myclass).Skip(1)
1 2 3
値または参照による変数渡し
メソッドを呼び出す場合、値または参照によって、そのメソッドに変数の値を渡すことができます。
通常、メソッドのシグニチャは、引数の参照渡しを意図しているかどうかを示します。以下に例を示します。
Method MyMethod(argument1, ByRef argument2, Output argument3)
ByRef キーワードは、参照によってこの引数を渡すことを示します。Output キーワードは、この引数を参照によって渡すことと、この引数に最初に指定した値がメソッドによってすべて無視されることを示します。
同様に、メソッドを定義するときに、メソッド・シグニチャで ByRef および Output キーワードを使用すると、そのメソッドの他のユーザに、それをどのように使用することを意図しているのかを知らせることができます。
ObjectScript で引数を参照渡しするには、そのメソッドを呼び出すときに変数名の前にピリオドを付けます。Python では、渡す値に対して iris.ref() を使用し、その参照に対してメソッドを呼び出します。これら両方を以下の例に示します。
do MyMethod(arg1, .arg2, .arg3)
arg2 = iris.ref("peanut butter")
arg3 = iris.ref("jelly")
MyMethod(arg1,arg2,arg3)
ByRef および Output キーワードは、インターシステムズ・クラス・リファレンスの利用者全員に役立つ情報を提供します。これらのキーワードは、コードの動作には影響しません。メソッドの呼び出し方法に関する規則を適用するのは、メソッドの作成者の責任です。
可変の引数
引数の個数を変えることができるメソッドを定義できます。以下に例を示します。
ClassMethod MultiArg(Arg1... As %List) [ Language = objectscript ]
{
set args = $GET(Arg1, 0)
write "Invocation has ",
args,
" element",
$SELECT((args=1):"", 1:"s"), !
for i = 1 : 1 : args
{
write "Argument[", i , "]: ", $GET(Arg1(i), "<NULL>"), !
}
}
ClassMethod MultiArg(Arg1... As %List) [ Language = Python ]
{
print("Invocation has", len(Arg1), "elements")
for i in range(len(Arg1)):
print("Argument[" + str(i+1) + "]: " + Arg1[i])
}
既定値の指定
ObjectScript または Python メソッドで引数の既定値を指定するには、以下の例に示す構文を使用します。
Method Test(flag As %Integer = 0)
{
//method details
}
メソッドが呼び出されるとき、引数が指定されていない場合は既定値を使用します (既定値が指定されている場合)。メソッドが Python で記述されている場合、既定値を持つ引数は、引数リストの末尾に定義する必要があります。
ObjectScript では、$GET 関数を使用して既定値を設定することもできます。以下に例を示します。
Method Test(flag As %Integer)
{
set flag=$GET(flag,0)
//method details
}
ただし、この方法ではシグニチャに影響しません。
クラス・メソッド呼び出しのショートカット
ObjectScript を使用してクラス・メソッドを呼び出す場合、以下のシナリオではパッケージ (または上位パッケージ) を省略できます。
-
参照が 1 つのクラス内であり、参照されるクラスが同じパッケージまたはサブパッケージ内にある場合。
-
参照が 1 つのクラス内であり、そのクラスが IMPORT 指示文を使用して、参照されるクラスを含むパッケージまたはサブパッケージをインポートする場合。
-
参照が 1 つのメソッド内であり、そのメソッドが IMPORT 指示文を使用して、参照されるクラスを含むパッケージまたはサブパッケージをインポートする場合。
ObjectScript からクラス・メソッドを呼び出す場合、以下のシナリオではパッケージ (または上位パッケージ) を省略できます。
-
%Library パッケージ内のクラスを参照している場合、これは特別に処理されます。クラス %Library.ClassName は %ClassName として参照できます。例えば、%Library.StringOpens in a new tab は %StringOpens in a new tab として参照できます。
-
User パッケージ内のクラスを参照している場合、これは特別に処理されます。例えば、User.MyClass は MyClass として参照できます。
インターシステムズでは、User パッケージにはクラスを提供していません。これは、ユーザが使用するために予約されています。
他の場合はすべて、常に完全なパッケージ名とクラス名を使用してクラス・メソッドを呼び出す必要があります。
Python からクラス・メソッドを呼び出す際、iris.cls() メソッドを使用している場合は、s = iris.cls('%String') のように、パッケージ (または上位パッケージ) を省略できます。iris.Package.Class を使用している場合は、s = iris._Library.String のように、より長い形式を使用します。