※当サイトの記事には、広告・プロモーションが含まれます。

PHP5.4から実装されたClosure::bind( )でprivateなプロパティ(メンバ変数)に外部からアクセス

PHPでは、PHP5ぐらいから、『オブジェクト指向プログラミング言語OOP)』、俗に言う『オブジェクト指向』の機能が充実してきました。

 

PHP: Hypertext Preprocessor

オブジェクト指向プログラミング

OOP(object-oriented programming)

相互にメッセージ(message) を送りあうオブジェクト (object) の集まりとしてプログラムを構成する技法である。

 

 

オブジェクト指向

オブジェクト指向では、すべてのモノや事柄を「オブジェクト」として捉えています。この時点ではクラスという概念がなくても、オブジェクトは存在します。

一方、インスタンスとはクラスという概念を具象化したものです。

概ね『オブジェクト』=『インスタンス』と考えていいと思われます。

 

クラス(class)

クラスベースオブジェクト指向においてオブジェクトの設計図にあたるもの。

抽象データ型の一つ。クラスから生成したオブジェクトのことをインスタンスという。

インスタンスの保持するデータ(メンバ変数、フィールドUMLでは「属性」ともいう))と操作(メソッドメンバ関数)が記述される。

アクセス範囲(public、private、protectedなど)や可変かどうか(final、 constantなど)等についても記述されている。

クラスは、継承ポリモーフィズムカプセル化などの、オブジェクト指向プログラミングにおける重要な概念を実現する強力な手段である。

 

クラスには

  • プロパティ(メンバ変数)⇐ 変数のこと
  • メソッド(メンバ関数)⇐ 関数のこと
  • 定数

を含むことができます。

 

メンバmember メンバー

メンバとは、構成員、会員、一部分、構成要素、部材、などの意味を持つ英単語。

オブジェクト指向プログラミングOOP)では、クラスやオブジェクトの持つ変数や関数などの要素をメンバ(「メンバ変数」「メンバ関数」など)ということがある。

一般の外来語としては「メンバー」と伸ばして表記するのが一般的だが、多くのIT用語と同じように、この意味で用いる場合には慣習的に「メンバ」と縮めて表記することが多い。

コーディングを支える技術」の西尾泰和氏によると、クラスには

の3つの役割があるといいます。 

 ⇩    詳しくは下記サイトへ

PHP7でクラスはバラバラになった : Architect Note

 

new演算子(オブジェクトの生成)

new演算子を使って、クラスを基にインスタンス(オブジェクト)を生成します。

 

例:クラスを定義し、new演算子でそのクラスのインスタンスを生成

<?php
/**
 * MyClass の定義
 */
class MyClass
{

 

// アクセス修飾子の異なるプロパティをそれぞれ設定
    public 
$public_access 'Public';
    protected 
$protected_access 'Protected';
    private 
$private_access 'Private';


// アクセス修飾子が指定されてないので自動的にpublicなメソッドになります
    function 
printHello()
    {
        echo 
$this->public_access;
        echo 
$this->protected_access;
        echo 
$this->private_access;
    }


}


// クラスMyClassのインスタンスを生成し、参照型変数$objに格納

// これで$obj->の形でMyClassのプロパティ、メソッドにアクセス可能

$obj = new MyClass();

// publicなプロパティにアクセス
echo 
$obj->public_access// 動作します

// protectedなプロパティにアクセス
echo $obj->protected_access// Fatal エラー

// privateなプロパティにアクセス
echo $obj->private_access// Fatal エラー

// printHello()は、publicなメソッドなので動作します
$obj->printHello(); // Public、Protected そして Private を表示します

 例:クラスに定数を含める

PHPで定数を定義するには"define"を使いますが、クラス内部で定義する場合には"const"の後に定数の名前を指定し、値を定義します。

(※変数のように"$"マークは定数名の頭には付きません。)

 

<?php

/* MyClassの定義 */

class MyClass
{

// 定数CONSTANTを定義
    const 
CONSTANT 'constant value';

    function 
showConstant() {

// クラス内から定数の値を参照(定数にアクセス)するには『self::定数名』
        echo  
self::CONSTANT "\n";
    }
}


// クラス外から定数へのアクセスは『クラス名::定数名』、クラスから直接可能
echo 
MyClass::CONSTANT "\n";

$classname "MyClass";
echo 
$classname::CONSTANT "\n"// PHP 5.3.0 以降で対応

$class = new MyClass();
$class->showConstant();
// クラス外から定数へのアクセスはクラスのオブジェクトからも可能
echo 
$class::CONSTANT."\n"// PHP 5.3.0 以降で対応


?>

 

PHP:クラスの基礎-Manual

privateはアクセス修飾子

アクセス修飾子は、プロパティとメソッドに指定するもので、プロパティとメソッドにどこからアクセスできるかという、アクセス権(visibility)を指定するものです。

アクセス修飾子をメンバ(プロパティ、メソッド)に指定することで、そのメンバが参照できる範囲(可視性)を限定する事ができます。

『public』『private』『protected』の3種類のキーワードがあります。

種類 説明
public どこからでもアクセス可能
private 定義するクラス内からのみアクセス可能
protected 定義するクラス内と、そのクラスを継承したクラスからアクセス可能

メソッドに何も指定しなかった場合はpublicとなります。

PHP4では、アクセス修飾子の機能はなく『var』が使われていて、『public』と同じく、どこからでもアクセス可能でした。

クラス内で自身のプロパティ、メソッドにアクセスする

自分自身のインスタンス$thisを使う場合

 例:MyClass自身のプロパティとメソッドにアクセス

<?php
/**
 * MyClass の定義
 */
class MyClass
{
    
// public コンストラクタの宣言
    
public function __construct() { }

    
// public メソッドの宣言
    
public function MyPublic() { }

    
// protected メソッドの宣言
    
protected function MyProtected() { }

    
// private メソッドの宣言
    
private function MyPrivate() { }

    
// これは public となります
    
function Foo()
    {
        
$this->MyPublic();
        
$this->MyProtected();
        
$this->MyPrivate();
    }
}

 

// クラスMyClassのインスタンスを生成し、参照型変数$myclassに代入

$myclass = new MyClass;

// piblicなメソッドMyPublic()にアクセス

$myclass->MyPublic(); // 動作します

// protectedなメソッドMyProtected()にアクセス

$myclass->MyProtected(); // Fatal エラー

// privateなメソッドMyPrivate()にアクセス

$myclass->MyPrivate(); // Fatal エラー

// publicなメソッドFoo()にアクセス

$myclass->Foo(); // MyPublic()、MyProtected() および MyPrivate() が動作します

?>

 

静的(static)なプロパティとメソッドが定義されてる場合

インスタンス化せずに使用するため、$this は使用できず、代わりに self を使用します。

例:self:: の使用

<?php

/* クラスAの定義 */

class {

// publicでstaticなメソッドを定義
    public static function 
who() {
        echo 
__CLASS__;
    }


    public static function 
test() {

// 自身のwho()メソッドにアクセス(who()メソッドを実行)
        
self::who();
    }


}

 

// クラスAを継承したクラスBを定義(『extends クラス名』で継承)
class 
extends {
    public static function 
who() {
        echo 
__CLASS__;
    }
}


// クラスBのtest()メソッドにアクセス(test()メソッドを実行)
B::test();


?>

 

 

 ⇩ クラスとかについて詳しくは下記サイトへ

 ・PHP入門-クラス

 

 ⇩ PHPマニュアルによる『static』の説明

static キーワード

クラスプロパティもしくはメソッドを static として宣言することで、 クラスのインスタンス化の必要なしにアクセスすることができます。
static なプロパティは、インスタンス化されたクラスオブジェクトから アクセスすることはできません (static なメソッドにはアクセスできます)。

static メソッド

static メソッドはオブジェクトのインスタンスを生成せずに コールすることができるので、疑似変数 は、 static として宣言されたメソッドの内部から利用することはできません。

 警告PHP 7 では、static でないメソッドを静的にコールすることが非推奨になりました。 E_DEPRECATED レベルの警告が発生します。 将来的にはサポートされなくなる見込みです。 

static プロパティ

static プロパティは、矢印演算子 -> によりオブジェクトからアクセス することはできません。

他の PHP 静的変数と同様、 静的プロパティの初期化はリテラルあるいは定数でのみ可能です。
式で初期化することはできません。 PHP 5.6 以降では、同じルールが const 式にも当てはまります。
コンパイル時に評価可能な、限られた式だけしか使えません。

PHP 5.3.0 以降では、変数を用いてクラスを参照することも可能です。
変数の値に (selfparentstatic といった) キーワードを指定することはできません。

 

話がだいぶ脱線しましたが、privateなプロパティ(メンバ変数)は定義するクラスの内のみからアクセス可能であるため、外部からアクセスできません。

外部からのアクセスを可能にするのが、『Closure::bind( )』(PHP5.4以降対応)

⇩  PHPマニュアルによる『Closure::bind( )』の説明

Closure::bind

(PHP 5 >= 5.4.0)

Closure::bindバインドされたオブジェクトとクラスのスコープでクロージャを複製する

 

説明

 public static Closure Closure::bind ( Closure $closure, object $newthis [, mixed $newscope = "static" ] )

このメソッドは、静的メソッド版の Closure::bindTo( ) です。 詳細な説明は Closure::bindTo( ) のドキュメントを参照ください 

パラメータ(引数)

closure($closure)

バインドする無名関数。

newthis($newthis)[データ型:object]

指定した無名関数をバインドするオブジェクト。
クロージャのバインドを解除するには NULL を指定します。

newscope($newscope)[データ型:mixed]

クロージャを関連づけるクラススコープ、あるいは 'static' で現在のスコープを維持します。
オブジェクトを渡した場合は、そのオブジェクトの型をその代わりに使います。
これは、バインドしたオブジェクトの protected メソッドや private メソッドの可視性を決めます。
このパラメータに、内部クラスのオブジェクトを渡すことはできません。

返り値

 新しい Closure オブジェクトを返します。 失敗した場合に FALSEを返します

 

バージョン 説明
7.0.0 newscope に内部クラスのオブジェクトを渡すことができなくなりました。 以前のバージョンでは、渡すことができていました。

例:

<?php

/* クラスAの定義 */

class {
    private static 
$sfoo 1;
    private 
$ifoo 2;
}

 

// staticでpublicな無名関数を$cl1に格納

// staticメソッドは『クラス名::メソッド名()』でアクセス可能

$cl1 = static function() {
    return 
A::$sfoo;
};

 

// publicな無名関数を$cl2に格納

// Closure::bind()で$cl2がAクラス内で処理されることになるので$this->の書き方が可能

$cl2 = function() {
    return 
$this->ifoo;
};


// 無名関数$cl1、$cl2をクラスAのクロージャ(クラスA内のメソッド)として処理します

$bcl1 Closure::bind($cl1null'A');
$bcl2 Closure::bind($cl2, new A(), 'A');


echo 
$bcl1(), "\n"// 1が表示されます
echo 
$bcl2(), "\n"// 2が表示されます


?>

 

第1引数に渡した関数内の処理は、第3引数に渡した名前のクラス内で実行されているものとして扱われるため、正常に関数を呼び出すことができています。

Closure::bind( )は無名関数に限り実行時コンテキストを動的に変更できるというチート機能を有しているのである。

 

⇩ Closure::bind( )について詳しくは下記サイトへ

【PHP】privateなメソッドを外部から実行する。

⇩ クロージャーに関しては下記サイトへ

なぜクロージャ(Closure)と言うのか?-Qiita

⇩    PHP5.4以前のprivateメソッドへのアクセス方法は下記サイトへ

phpunitでprivateなstatic関数をテストする - かけるヒトからできるヒト

⇩    コンテキストとは?

コンテキスト(Context)の意味がさっぱり分かりません。- php | 教えて!goo

 

内部クラス(※Javaでの説明なので、PHPにも当てはまるか分かりません)

内部クラスは、クラスの内部にネストしてクラスを定義する機能である。

クラスの内部にクラスを定義することにより、クラス間の関係を、クラスの継承関係とはまた別に、従属関係、親子関係で表現する事ができる。

また、内部クラスにprivate修飾子を付ける事により、内部クラスの外側のクラス(アウタークラス)からしかアクセスできないようにクラスを隠蔽するこもできる。

 

結論として、引数のnewscopeの説明が特に分からんです。(それ以外の説明も。)

説明にある『内部クラスのオブジェクト』ってどれのこと?

PHPマニュアル、もう少し初学者にも分かりやすくして欲しいっす。

 

 

チートcheat

チートとは、いかさま、ごまかし、詐欺、不正行為などの意味を持つ英単語。

ビデオゲームなどで、非公開の機能や非正規のツールなどを用いて、本来の機能として提供されていない自動操作を行ったり、パラメータやアイテムなどゲーム内の状態を任意に変更するといった行為を俗にチートという。

MMORPGなど多人数が参加するオンラインゲームにおいて、クライアントソフトに改造を施したり、動作を解析して開発した特殊なツールを使い、キャラクターを自動操縦したり、強さなどを表すパラメータを不正に操作したり、アイテムやゲーム内通貨を不正に入手することをチート行為という。

チートは多くの場合は規約によって禁じられており、発見されるとアカウントを剥奪されたり、不正に入手したアイテムなどを没収されたりといった罰則が与えられることが多い。

ただし、運営元の対応が不完全だったり、チート行為に対する姿勢があいまいだったりして、ユーザコミュニティとトラブルになる例もある。

また、エミュレータを利用して家庭用ゲーム機向けのゲームソフトをパソコンでプレイする際に、エミュレータの機能や改造ツールなどを用いて、キャラクターのパラメータを任意の値に設定したり、ゲーム自体に改造を加えることで、本来は不可能な遊び方をすることもチートという。

最近では、正規のゲームソフト自体に、特定のコマンドを入力することでキャラクターを最強の状態にするといった機能が実装されていることがあり、この機能のことをチート、入力するコマンド(多くの場合は非公開)のことをチートコードという。