ASP.NET Calendarを使用した日付入力

カレンダーから日付を選択できる日付入力テキストボックスを定義する方法です。
あちこちサンプルはあるんですが、まとまった情報がなかったので自分用にメモしておきます。

Calendarを使用した日付入力

参考サイトはコチラ。
@IT [ASP.NET AJAX]MaskedEditコントロールでテキストボックスに入力可能な値を制限するには?[2.0、3.0、3.5、C#、VB]
@IT [ASP.NET AJAX]Calendarコントロールで日付入力ボックスを定義するには?[2.0のみ、C#、VB]

サンプルとして以下のような画面を作成してみます。
テキストボックスには日付を入力することもカレンダーから日付を選択することもできます。
日付以外を入力するとエラーが表示されます。

まずはDefault.aspxのソースです。
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="Calendar._Default" %>

<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <style>
        .cal_Theme1 .ajax__calendar_container
        {
            background-color: #e2e2e2;
            border: solid 1px #cccccc;
        }
        .cal_Theme1 .ajax__calendar_header
        {
            background-color: #ffffff;
            margin-bottom: 4px;
        }
        .cal_Theme1 .ajax__calendar_title, .cal_Theme1 .ajax__calendar_next, .cal_Theme1 .ajax__calendar_prev
        {
            color: #004080;
            padding-top: 3px;
        }
        .cal_Theme1 .ajax__calendar_body
        {
            background-color: #e9e9e9;
            border: solid 1px #cccccc;
        }
        .cal_Theme1 .ajax__calendar_dayname
        {
            text-align: center;
            font-weight: bold;
            margin-bottom: 4px;
            margin-top: 2px;
        }
        .cal_Theme1 .ajax__calendar_day
        {
            text-align: center;
        }
        .cal_Theme1 .ajax__calendar_hover .ajax__calendar_day, .cal_Theme1 .ajax__calendar_hover .ajax__calendar_month, .cal_Theme1 .ajax__calendar_hover .ajax__calendar_year, .cal_Theme1 .ajax__calendar_active
        {
            color: #004080;
            font-weight: bold;
            background-color: #ffffff;
        }
        .cal_Theme1 .ajax__calendar_today
        {
            font-weight: bold;
        }
        .cal_Theme1 .ajax__calendar_other, .cal_Theme1 .ajax__calendar_hover .ajax__calendar_today, .cal_Theme1 .ajax__calendar_hover .ajax__calendar_title
        {
            color: #bbbbbb;
        }
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server" EnableScriptGlobalization="True" />
    <div>
        <asp:TextBox ID="txtDate" runat="server" Width="100" />
        <asp:MaskedEditExtender ID="meeDate" runat="server" TargetControlID="txtDate" Mask="9999/99/99"
            MaskType="Date" UserDateFormat="YearMonthDay" />
        <asp:ImageButton ID="imgbtnCalendar" runat="server" ImageUrl="~/image/calendar.png"
            OnClientClick="return false;" />
        <asp:CalendarExtender ID="ceDate" runat="server" Format="yyyy/MM/dd" TargetControlID="txtDate"
            PopupButtonID="imgbtnCalendar" CssClass="cal_Theme1" />
        <asp:TextBox ID="TextBox1" runat="server"/>
        <asp:Button ID="btnExec" runat="server" Text="送信" />
        <br />
        <asp:RangeValidator ID="vranDate" runat="server" ControlToValidate="txtDate" Display="Dynamic"
            Type="Date" MinimumValue="1900/01/01" MaximumValue="9999/12/31" ErrorMessage="正しい日付を入力して下さい。"/>
    </div>
    </form>
</body>
</html>

まずはToolkitScriptManager を配置します。
カレンダーを日本語表示するためにEnableScriptGlobalizationプロパティをTrueに設定します。

日付を入力するためのテキストボックスを配置します。(ID:txtDate)

テキストボックスに日付入力の制限をかけるために、MaskedEditExtenderを配置します。(ID:meeDate)
以下のプロパティを設定します。
TargetControlID="txtDate"
Mask="9999/99/99"
MaskType="Date"
UserDateFormat="YearMonthDay"

カレンダーを表示するためのImageButtonを配置します。(ID:imgbtnCalendar)
OnClientClick="return false;"を設定し、サーバーサイドの処理を発生させないようにします。

カレンダーとなるCalendarExtenderを配置します。(ceDate)
以下のプロパティを設定します。
Format="yyyy/MM/dd"
TargetControlID="txtDate"
PopupButtonID="imgbtnCalendar"
CssClass="cal_Theme1"
※CssClassは別に設定しなくてもいいです。
「CalendarExtender css」で検索すると、いろいろ見つかります。

フォーカス移動させるためのTextBox(ID:TextBox1)と送信ボタン(ID:btnExec)を配置します。

日付が正しい形式であるかを検証するためにRangeValidatorを使用します。(ID:vranDate)
以下のプロパティを設定します。
ControlToValidate="txtDate"
Type="Date"
MinimumValue="1900/01/01"
MaximumValue="9999/12/31"
ErrorMessage="正しい日付を入力して下さい。"


以上でカレンダーを使用した日付入力の完成です。

ASP.NET モーダル画面の表示(ModalPopupExtender)

また久しぶりの投稿です。
PHPのお仕事が来るということでPHPの勉強をしていたのですが、来たのはASP.NETのお仕事でした。
ASP.NET久しぶりです。
最後にASP.NETで開発したのが2008年だから、5年ぶりだぁ(;´∀`)
もう記憶がほとんどないです。

ということで、今回の開発で詰まったところを、次回の開発のためにメモしておきます。
次のASP.NETのお仕事はいつかしら・・・

モーダル画面を表示

AjaxControlToolkitのModalPopupExtenderコントロールを使用してモーダル画面を表示する方法はコチラ。
@IT [ASP.NET AJAX]ModalPopupコントロールでモーダル・ウィンドウを生成するには?

サンプルとしてModalPopupExtenderを使用し、以下のようなメッセージダイアログを作成してみます。

まずはimageフォルダに質問、情報、警告、エラー時にメッセージに表示するアイコン画像を保存します。


メッセージダイアログ部分をユーザーコントロールで作成します。
「新しい項目の追加」 > 「Webユーザーコントロール」を選択します。
ファイル名は「Message.ascx」とします。

Message.ascxのソース
<%@ Control Language="vb" AutoEventWireup="false" CodeBehind="Message.ascx.vb" Inherits="ModalPopupExtenderSample.Message" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>

<!-- ダミーボタン(非表示) -->
<asp:Button ID="btnDummy" runat="server" Text="Button" Style="display: none" />
<!-- ポップアップ部分 -->
<asp:Panel ID="pnlDialog" runat="server">
    <div class="dialog">
        <div class="title">
            <asp:Label ID="lblTitle" runat="server"></asp:Label>
        </div>
        <div class="content">
            <div class="icon">
                <asp:Image ID="Image1" runat="server" ImageUrl="" /></div>
            <div class="message">
                <asp:Label ID="lblMsg" runat="server"></asp:Label></div>
        </div>
        <br class="clearfloat" />
        <div class="button">
            <asp:Button ID="btnOk" runat="server" Text="OK" />
            <asp:Button ID="btnYes" runat="server" Text="Yes" />
            <asp:Button ID="btnNo" runat="server" Text="No" />
        </div>
    </div>
</asp:Panel>
<!-- ModalPopupExtender -->
<asp:ModalPopupExtender ID="modal" runat="server" TargetControlID="btnDummy" PopupControlID="pnlDialog"
    DropShadow="true" Drag="false" PopupDragHandleControlID="pnlDialog" BackgroundCssClass="modalBackground">
</asp:ModalPopupExtender>
Message.ascxのコード
Public Partial Class Message
    Inherits System.Web.UI.UserControl

    'ダイアログが閉じられたときに発生するイベントです。
    Public Event DialogClosed(ByVal dialogResult As DialogResultType, ByVal source As String, ByVal args() As Object)

    'ダイアログの表示タイプを示す列挙帯です。
    Public Enum StyleType
        Warning
        Information
        [Error]
        Question
    End Enum

    'ダイアログのどのボタンが押されたかを示す列挙帯です。
    Public Enum DialogResultType
        OK
        Yes
        No
    End Enum

    'ダイアログの表示スタイルです。
    Private _Style As StyleType
    'ダイアログのタイトルです。
    Private _sTitle As String
    'ダイアログのメッセージです。
    Private _sMessage As String

    'ダイアログの表示スタイルを取得・設定します。
    Public Property Style() As StyleType
        Get
            Return Me._Style
        End Get
        Set(ByVal value As StyleType)
            Me._Style = value
            'アイコン
            Dim url As String = String.Empty
            Select Case _Style
                Case StyleType.Warning
                    url = "~/image/warning.png"
                Case StyleType.Information
                    url = "~/image/info.png"
                Case StyleType.Error
                    url = "~/image/error.png"
                Case StyleType.Question
                    url = "~/image/question.png"
            End Select
            Me.Image1.ImageUrl = url
            'ボタン
            Select Case _Style
                Case StyleType.Question
                    Me.btnOk.Visible = False
                    Me.btnYes.Visible = True
                    Me.btnNo.Visible = True
                Case Else
                    Me.btnOk.Visible = True
                    Me.btnYes.Visible = False
                    Me.btnNo.Visible = False
            End Select
        End Set
    End Property
    'タイトルを取得・設定します。
    Public Property Title() As String
        Get
            Return Me._sTitle
        End Get
        Set(ByVal value As String)
            Me._sTitle = value
            Me.lblTitle.Text = value
        End Set
    End Property
    'メッセージを取得・設定します。
    Public Property Message() As String
        Get
            Return Me._sMessage
        End Get
        Set(ByVal value As String)
            Me._sMessage = value
            Me.lblMsg.Text = value
        End Set
    End Property
    'ダイアログを呼び出したオブジェクトを取得・設定します。
    Public Property Source() As String
        Get
            Return DirectCast(ViewState("Source"), String)
        End Get
        Set(ByVal value As String)
            ViewState("Source") = value
        End Set
    End Property
    'ダイアログを呼び出した際、任意の引数を取得・設定します。
    Public Property Args() As Object()
        Get
            Return DirectCast(ViewState("args"), Object())
        End Get
        Set(ByVal value As Object())
            ViewState("args") = value
        End Set
    End Property

    'ダイアログを表示します。
    Public Sub Show()
        Me.modal.Show()
    End Sub

    'Yesボタンが押された時の処理です。
    Private Sub btnYes_Command(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.CommandEventArgs) Handles btnYes.Command
        RaiseEvent DialogClosed(DialogResultType.Yes, Me.Source, Me.Args)
    End Sub
    'Noボタンが押された時の処理です。
    Private Sub btnNo_Command(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.CommandEventArgs) Handles btnNo.Command
        RaiseEvent DialogClosed(DialogResultType.No, Me.Source, Me.Args)
    End Sub
    'OKボタンが押された時の処理です。
    Private Sub btnOk_Command(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.CommandEventArgs) Handles btnOk.Command
        RaiseEvent DialogClosed(DialogResultType.OK, Me.Source, Me.Args)
    End Sub

End Class

次にダイアログ画面を呼び出す親画面です。

親画面を「Default.aspx」とします。
ToolkitScriptManager を「form」タグの先頭に配置します。
先ほど作成したMessageユーザーコントロールを配置します。

Default.aspxのソース
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="ModalPopupExtenderSample._Default" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>
<%@ Register Src="Message.ascx" TagName="Message" TagPrefix="uc1" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <asp:ToolkitScriptManager ID="ToolkitScriptManager1" runat="server" />
    <div>
        <asp:Button ID="btnQuestion" runat="server" Text="Question" />
        <asp:Button ID="btnWarning" runat="server" Text="Warning" />
        <asp:Button ID="btnInformation" runat="server" Text="Information" />
        <asp:Button ID="btnError" runat="server" Text="Error" />
        <br />
        <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
        <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
        
        <uc1:Message ID="Message1" runat="server" />
    </div>
    </form>
</body>
</html>
Default.aspxのコード
Partial Public Class _Default
    Inherits System.Web.UI.Page

    Private Sub btnQuestion_Command(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.CommandEventArgs) _
    Handles btnQuestion.Command
        Me.Message1.Style = Message.StyleType.Question
        Me.Message1.Title = "タイトル"
        Me.Message1.Message = "質問メッセージ。よろしいですか?"
        Me.Message1.Source = Me.btnQuestion.ClientID
        Me.Message1.Args = New Object() {"args1", "args2"}
        Me.Message1.Show()
    End Sub
    Private Sub btnWarning_Command(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.CommandEventArgs) _
    Handles btnWarning.Command
        Me.Message1.Style = Message.StyleType.Warning
        Me.Message1.Title = "タイトル"
        Me.Message1.Message = "警告メッセージ"
        Me.Message1.Source = Me.btnWarning.ClientID
        Me.Message1.Args = New Object() {"args3", "args4"}
        Me.Message1.Show()
    End Sub
    Private Sub btnInformation_Command(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.CommandEventArgs) _
    Handles btnInformation.Command
        Me.Message1.Style = Message.StyleType.Information
        Me.Message1.Title = "タイトル"
        Me.Message1.Message = "情報メッセージ"
        Me.Message1.Source = Me.btnInformation.ClientID
        Me.Message1.Args = New Object() {"args5", "args6"}
        Me.Message1.Show()
    End Sub
    Private Sub btnError_Command(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.CommandEventArgs) _
    Handles btnError.Command
        Me.Message1.Style = Message.StyleType.Error
        Me.Message1.Title = "タイトル"
        Me.Message1.Message = "エラーメッセージ"
        Me.Message1.Source = Me.btnError.ClientID
        Me.Message1.Args = New Object() {"args7", "args8"}
        Me.Message1.Show()
    End Sub

    Private Sub Message1_DialogClosed(ByVal dialogResult As Message.DialogResultType, ByVal source As String, ByVal args() As Object) _
    Handles Message1.DialogClosed
        Select Case source
            Case Me.btnQuestion.ClientID
                If dialogResult <> Message.DialogResultType.Yes Then
                    Return
                End If
                Me.Label1.Text = args(0).ToString

            Case Me.btnWarning.ClientID
                If dialogResult <> Message.DialogResultType.OK Then
                    Return
                End If
                Me.Label1.Text = args(0).ToString

            Case Me.btnInformation.ClientID
                If dialogResult <> Message.DialogResultType.OK Then
                    Return
                End If
                Me.Label1.Text = args(0).ToString

            Case Me.btnError.ClientID
                If dialogResult <> Message.DialogResultType.OK Then
                    Return
                End If
                Me.Label1.Text = args(0).ToString

        End Select
    End Sub
End Class
次にスタイルシートです。

「App_Themes」フォルダに「追加」>「ASP.NETフォルダの追加」>「Theme」を選択し、テーマ「theme1」を追加します。
「Theme1」フォルダに「追加」>「新しい項目」より「スタイルシート」を追加します。
ファイル名は「StyleSheet1.css」としました。

Default.aspxにテーマを設定するためweb.configを編集します。
<pages>ノードを探し、以下のように「theme="theme1"」を追加します。
<pages theme="theme1">
「StyleSheet1.css」の中身です。
.dialog { 
    background-color: #F0FFFF;
    width: 400px;
    min-width: 400px;
}
.dialog .title{ 
    background-color: #B0C4DE;
    padding: 5px 10px;
}
.dialog .content 
{
    width: 380px;
    padding: 10px;
    margin-bottom: 10px;
}
.dialog .icon
{
    float: left;
    width: 48px;
    margin-right: 12px;
}
.dialog .message
{
    float: left;
    width: 320px;
 word-break: break-all; /* 表示範囲に合わせて改行 */
    word-wrap: break-word; /* 必要に応じて単語の途中で改行する */
}    
.dialog .button
{
    padding: 10px 0;
    text-align: center;
}
.modalBackground
{
    background-color:black;
    filter:alpha(opacity=75); /* IE:透明度 透明にしちゃうと親画面が操作できてしまうので注意 */
    opacity:0.75;            /* Opera・Safari:透明度 */
    zoom:1;                  /* ModalPopupExtenderでポップアップ表示した際、親画面の背景スタイルがCSSで定義しても生きない(IEのみ)。有効にを適用させるために必要。*/
}

キモになるのは「.modalBackground」です。 「.modalBackground」はユーザーコントロール「Message.ascx」のソースで、ModalPopupExtenderのBackgroundCssClassプロパティに設定しています。
<!-- ModalPopupExtender -->
<asp:ModalPopupExtender ID="modal" runat="server" TargetControlID="btnDummy" PopupControlID="pnlDialog"
    DropShadow="true" Drag="false" PopupDragHandleControlID="pnlDialog" BackgroundCssClass="modalBackground">
</asp:ModalPopupExtender>
メッセージダイアログがポップアップ表示した際、親画面のスタイルを定義します。
まず半透明にしないと、メッセージダイアログを表示した際に親画面が操作できてしまいます。
次にスタイルシートでmodalBackgroundを定義すると、親画面が半透明になりません。
半透明にするためには「zoom:1」とするとよいそうです。
スタイルシートではなくMessage.ascx自体にmodalBackgroundのスタイルを定義するときは「zoom:1」は必要ありません。

今回ハマったのはスタイルシート「.modalBackground」の定義でした(ノД`)・゜・。


追記
ASP.NET ModalPopupExtenderでDataGridをポップアップ表示し選択した値を元の画面に設定する

PHP 例外処理

例外処理

PHP5から例外処理としてtry~catch構文が使えるようになりました。
PHP5.5以前はfinally句は使用できませんが、PHP5.5以降からはfinally句も指定できます。

PHP5.5以前
try {
    例外が発生するかもしれない処理;
} catch (発生するかもしれない例外の種類  変数名) {
    例外発生時の処理;
}
PHP5.5以降
try {
    例外が発生するかもしれない処理;
} catch (発生するかもしれない例外の種類  変数名) {
    例外発生時の処理;
} finally {
    例外が発生しても発生しなくても必ず行う処理。
}

例外を発生させるにはthrowキーワードを使います。
throw new ExceptionまたはExceptionのサブクラス(コンストラクタ引数);


使用例
<?php
//例外をThrowする
class MyClass {
    public function Method1() {
        $this->Method2();
    }
    
    private function Method2() {
        throw new Exception('例外が発生しました。');
    }
}

//例外をcatchする
$obj = new MyClass();
try {
    $obj->Method1();
} catch (Exception $e) {
    print($e->getMessage());
}
?>
実行結果


ExceptionクラスにはgetMessage()メソッドのほかにも以下のようなメソッドがあります。
getMessage例外メッセージ
getCode例外コード
getFile例外を発生したファイル名
getLine例外を発生した行数
getTraceバックトレース(配列)
getTraceAsStringバックトレース(文字列)


例外クラスを継承し独自の例外を作成する

Exceptionクラスまたはそのサブクラスを継承し独自の例外を作成することができます。
//独自例外クラス
class MyException extends Exception {}

//独自例外をThrowする
class MyClass {
    public function Method1() {
        $this->Method2();
    }
    
    private function Method2() {
        throw new MyException('例外が発生しました。');
    }
}

//独自例外をcatchする
$obj = new MyClass();
try {
    $obj->Method1();
} catch (MyException $e) {
    print($e->getMessage());
}


PHPにはExceptionのサブクラスとして以下のような例外が用意されています。
LogicExceptionは開発者が間違ったコードを実装したときに発生させる例外です。
たとえばあるメソッドは引数に数値を想定して作成しているのに、数値に変換できないような文字列が引数に指定されたときはLogicExceptionまたはそのサブクラスをthrowする。
RuntimeExceptionは実行時にしか発生しない例外で通常の例外です。
  • LogicException
    • BadFunctionCallException・・・未定義の関数をコールバックが参照したり、引数を指定しなかったりした場合にスローされる例外です。
      • BadMethodCallException・・・未定義のメソッドをコールバックが参照したり、引数を指定しなかったりした場合にスローされる例外です。
    • DomainException・・・定義したデータドメインに値が従わないときにスローされる例外です。
    • InvalidArgumentException・・・引数が期待値に一致しなかった場合にスローされる例外です。
    • LengthException・・・長さが無効な場合にスローされる例外です。
    • OutOfRangeException・・・無効なインデックスを要求した場合にスローされる例外です。
  • RuntimeException
    • OutOfBoundsException・・・値が有効なキーでなかった場合にスローされる例外です。
    • OverflowException・・・いっぱいになっているコンテナに要素を追加した場合にスローされる例外です。
    • RangeException・・・・プログラムの実行時に範囲エラーが発生したことを示すときにスローされる例外です。
    • UnderflowException・・・空のコンテナ上で無効な操作 (要素の削除など) を試みたときにスローされる例外です。
    • UnexpectedValueException・・・いくつかの値のセットに一致しない値であった際にスローされる例外です。

PHP インターフェース

インターフェース

インターフェースを定義するにはclassキーワードの代わりにinterfaceキーワードを使用します。
インターフェース内のメソッドは抽象メソッドになるので、メソッドの宣言だけを定義し、処理内容は定義しません。
メソッドにはabstractキーワードは付けません。
アクセス修飾子はpublicのみが指定できます。
interface インターフェース名 {
    public function メソッド名($arg1);
}

インターフェースを実装するにはimplementsキーワードを使用します。
複数のインターフェースを実装するにはインターフェース名をカンマで区切ります。
インターフェースを実装したクラスは、インターフェースに定義されているメソッドをすべてオーバーライドする必要があります。
メソッドをオーバーライドしたとき、引数はオーバーライド元のメソッドと同じにするか、省略可能な引数を追加することができます。
class クラス名 implements インターフェース名1, インターフェース名2 {
    public function メソッド名($arg1, $arg2=''){
        処理内容;
    };
}

コンストラクタもインターフェースで定義することができます。
マニュアルには「ひとつのクラスの中で、同じ名前の関数を含む 2 つのインターフェイスを 実装することはできません。あいまいさを解決できなくなるためです。」とありましたが 、実装してもエラーにはならないようです。
<?php
//インターフェース1
interface MyInterface1 {
    public function Method();
    public function Method1($value);
    public function __construct();
}
//インターフェース2
interface MyInterface2 {
    public function Method();
    public function Method2($value);
}
//インターフェースを実装したクラス
class MyClass implements MyInterface1, MyInterface2 {

    public function Method1($value, $str='') { print('Method1</br>'); }
    
    public function Method2($value, $str='') { print('Method2</br>'); }
    
    public function Method(){ print('Method</br>'); }
    
    public function __construct($str=''){}
}
//使用例
$obj = new MyClass();
$obj->Method();
$obj->Method1(1);
$obj->Method2(2);
?>
実行結果


インターフェースを継承し新たなインターフェースを作成することができます。
<?php
//親インターフェース
interface ParentInterface {
    public function Method1();
}
//子インターフェース
interface ChildInterface extends ParentInterface {
    public function Method2();
}
//親インターフェースを実装したクラス
class Class1 implements ParentInterface {

    public function Method1() { print('Method1</br>'); }
    
}
//子インターフェースを実装したクラス
class Class2 implements ChildInterface {

    public function Method1() { print('Method1</br>'); }
    
    public function Method2() { print('Method2</br>'); }
    
}
//使用例
print('-----Class1-----</br>');
$class1 = new Class1();
$class1->Method1();

print('-----Class2-----</br>');
$class2 = new Class2();
$class2->Method1();
$class2->Method2();
?>
実行結果

PHP abstract修飾子

abstract修飾子

abstract修飾子をつけることができるのはクラスとメソッドのみです。

クラスにabstract修飾子をつけると、そのクラスはインスタンス化できません。
abstractクラスにabstractメソッドを含める必要はありません。
<?php
//親クラス(抽象クラス)
abstract class ParentClass {
    public function ParentMethod(){
        print('ParentMethod</br>');
    }
}
//子クラス
class ChildClass extends ParentClass{
}>


//使用例

//ParentClassはインスタンス化できない。
//$parent = new ParentClass();

//ParentClassを継承したChildClassをインスタンス化する。
$child = new ChildClass();
$child->ParentMethod();
?>


メソッドにabstract修飾子をつけると、そのメソッドはサブクラスで必ずオーバーライドしなければなりません。
abstractメソッドを定義しているクラスはabstract修飾子をつけなければなりません。
abstractメソッドはメソッド定義だけを宣言し、処理内容は定義しません。
abstractメソッドをオーバーライドした際のアクセス修飾子は、abstractメソッドで定義した修飾子より同じか緩くする必要があります。
たとえばprotectedで定義したabstractメソッドをオーバーライドするときは、protectedまたはpublicにします。
abstractメソッドをオーバーライドしたとき、引数はabstractメソッドと同じにするか、省略可能な引数を追加することができます。

コンストラクタもabstract修飾子をつけることができます。
PHP5.4以前ではコンストラクタの引数はオーバーライド元のメソッドと違ってもよかったようですが、PHP5.4以降からは引数は同じか、省略可能な引数を追加することができます。
<?php
//親クラス(抽象クラス)
//abstractメソッドを定義しているクラスはabstract修飾子をつける
abstract class ParentClass {
    
    //abstractメソッドはメソッド定義だけを宣言し、処理内容は定義しません。
    protected abstract function AbstractMethod($value);
    
    //コンストラクタもabstractメソッドにすることができます。
    protected abstract function __construct();
}
//子クラス
class ChildClass extends ParentClass {
    //abstractメソッドをオーバーライド
    //アクセス修飾子は、abstractメソッドで定義した修飾子より同じか緩くする
    //引数はabstractメソッドと同じにするか、省略可能な引数を追加することができます
    public function AbstractMethod($value, $str='') {
    }
    
    //コンストラクタをオーバーライド
    //引数はabstractメソッドと同じにするか、省略可能な引数を追加することができます
    public function __construct($str=''){
    }
}
?>

PHP final修飾子

final修飾子

final修飾子をつけることができるのはクラスとメソッドのみです。
クラスにfinal修飾子をつけると、そのクラスは継承できません。
メソッドにfinal修飾子をつけると、そのメソッドは子クラスでオーバーライドできません。
コンストラクタ、アクセッサもメソッドの一種なのでfinal修飾子をつけることがきます。


クラスにfinal修飾子をつけると、そのクラスは継承できません。
<?php
final class ParentClass {
}
//継承するとエラーになります。
class ChildClass extends ParentClass {
}
?>

メソッドにfinal修飾子をつけると、そのメソッドは子クラスでオーバーライドできません。
<?php
class ParentClass {
    public final function Method(){}
}

class ChildClass extends ParentClass {
    //オーバーライドするとエラー
    public function Method() {}
}
?>

コンストラクタにfinal修飾子をつけると、そのコンストラクタは子クラスでオーバーライドできません。
<?php
class ParentClass {
    public final function __construct(){}
}

class ChildClass extends ParentClass {
    //オーバーライドするとエラー
    public function __construct(){}
?>


PHP 継承とオーバーライド

継承

クラスを継承するにはextendsキーワードを使用します。
多重継承はできません。
構文
class 子クラス extends 親クラス {
}


インスタンスメンバをオーバーライド

子クラスでメソッドをオーバーライドしなかった場合、親クラスのメソッドが呼び出されます。
子クラスから親クラスのメンバにアクセスするには「parent::」を利用します。

コンストラクタもメソッドと同じで、
子クラスでコンストラクタを定義しない場合は、親クラスのコンストラクタが継承されます。
子クラスでコンストラクタを定義した場合は親クラスのコンストラクタは自動で呼び出されませんので、親クラスのコンストラクタを明示的に呼び出す必要があります。
親クラスのコンストラクタを呼ばなくてもエラーにはなりません。
<?php
//親クラス
class ParentClass {
    protected $instanceField = 0;
    
    public function __construct($instanceField) {
        print('ParentClass:Construct</br>');
        $this->instanceField = $instanceField;
    }
    
    public function showInstanceField() {
        print($this->instanceField .'</br>');
    }
}
//子クラス1
//親クラスのメソッド、コンストラクタをオーバーライドしない。
class ChildClass1 extends ParentClass {
}

//子クラス2
//親クラスのメソッド、コンストラクタをオーバーライドする。
class ChildClass2 extends ParentClass {
    public function __construct() {
        print('ChildClass2:Construct</br>');
        $this->instanceField = 2;
    }
    
    public function showInstanceField() {
        print('ChildClass2:showInstanceField</br>');
        print($this->instanceField .'</br>');
    }
}
//子クラス3
//親クラスのメソッド、コンストラクタをオーバーライドし、親クラスのメソッドを利用する。
class ChildClass3 extends ParentClass {
    public function __construct() {
        print('ChildClass3:Construct</br>');
        parent::__construct(3);
    }
    
    public function showInstanceField() {
        print('ChildClass3:showInstanceField</br>');
        parent::showInstanceField();
    }
}


//使用例
print('-----子クラス1-----</br>');
$child1 = new ChildClass1(1);
$child1->showInstanceField();

print('-----子クラス2-----</br>');
$child2 = new ChildClass2();
$child2->showInstanceField();

print('-----子クラス3-----</br>');
$child3 = new ChildClass3();
$child3->showInstanceField();
?>
実行結果



スタティックメンバのオーバーロード

スタティックなメンバもインスタンスメンバと同じく、
子クラスでメソッドをオーバーライドしなかった場合、親クラスのメソッドが呼び出されます。
子クラスから親クラスのスタティックメンバにアクセスするには「parent::」を利用します。
子クラスで親クラスのメンバをオーバーライドしなかった場合は「self::」を利用することもできます。
<?php
//親クラス
class ParentClass {
 protected static $staticField = 5;
 
 public function __construct() {
  print('ParentClass:Construct</br>');
 }
 
 public static function showStaticField() {
  print(self::$staticField .'</br>');
 }
}
//子クラス1
//親クラスのスタティックメソッドをオーバーライドしない。
class ChildClass1 extends ParentClass { 
}

//子クラス2
//親クラスのスタティックメソッドをオーバーライド
//スタティック変数はオーバーライドしていないので「parent::」でも「self::」でアクセス可能。
class ChildClass2 extends ParentClass {
 public static function showStaticField() {
  print('ChildClass2:showStaticField' .'</br>');
  print(self::$staticField .'</br>');
 }
}
//子クラス3
//親クラスのスタティック変数、スタティックメソッドをオーバーライド
//「parent::」では親クラスのスタティック変数を参照し、「self::」では自クラスのスタティック変数を参照する。
class ChildClass3 extends ParentClass {
 protected static $staticField = 3;
 
 public static function showStaticField() {
     print('ChildClass3:showStaticField' .'</br>');
  print(self::$staticField .'</br>');
  print(parent::$staticField .'</br>');
 }
}


//使用例
print('-----子クラス1-----</br>');
ChildClass1::showStaticField();

print('-----子クラス2-----</br>');
ChildClass2::showStaticField();

print('-----子クラス3-----</br>');
ChildClass3::showStaticField();

?>
実行結果