Skip to content

Instantly share code, notes, and snippets.

@fivestar
Created May 27, 2010 02:01
Show Gist options
  • Save fivestar/415344 to your computer and use it in GitHub Desktop.
Save fivestar/415344 to your computer and use it in GitHub Desktop.
<?php
/**
* インスタンス変数を参照しているメソッドをstaticとして呼び出した場合はエラーになる・・・
* そんなふうに考えていた時期が俺にもありました
*
* @see Symfony\Components\Form\HybridForm
*/
ini_set('display_errors', 'on');
error_reporting(-1);
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});
class Field
{
protected $data;
function initialize($data)
{
$this->data = $data;
var_dump(__METHOD__);
}
}
class FieldGroup extends Field
{
function initialize($data)
{
parent::initialize($data);
var_dump(__METHOD__);
}
}
class HybridField extends FieldGroup
{
const FIELD = 0;
const GROUP = 1;
private $mode = self::FIELD;
function setMode($mode)
{
$this->mode = $mode;
}
function initialize($data)
{
if ($this->mode == self::GROUP) {
parent::initialize($data);
} else {
// わろす
Field::initialize($data);
}
var_dump($this->data);
}
}
$field = new HybridField();
$field->initialize(array('foo' => 'bar'));
$group = new HybridField();
$group->setMode(HybridField::GROUP);
$group->initialize(array('bar' => 'baz'));
// string(17) "Field::initialize"
// array(1) {
// ["foo"]=>
// string(3) "bar"
// }
// string(17) "Field::initialize"
// string(22) "FieldGroup::initialize"
// array(1) {
// ["bar"]=>
// string(3) "baz"
// }
/**
解説
======
ここではField, FieldGroup, HybridFieldの3つのクラスを定義しています。
HybridFieldはFieldGroupの子クラスにあたり、FieldGroupはFieldの子クラスにあたります。
普通に考えたら、HybridFieldはFieldGroupの子クラスなので、さらにその親であるFieldのメソッドは呼び出せません。
ではHybridFieldのinitialize()メソッドをみてください。
Field::initialize($data);
こんな記述が。Fieldクラスのinitialize()はインスタンスメソッドです。
通常、インスタンスメソッドをstatic呼び出しした場合はエラーが出ますが、
実はクラスの内部からであればstatic呼び出しが可能です。
そして何よりも理解できないのが、Fieldのinitialize()は内部でプロパティの値を変更する、
という処理を行っています。Field::initialize($data)という呼び出しはstaticとして呼び出しているので
内部の$thisって変数は定義されていないのでは?と思うわけです。
しかし。なんてこったい。Field::initialize()が参照している$thisには、
それを呼び出したHybridFieldのインスタンスが入っているではありませんか。
つまり、おじいちゃんのメソッドだろうとひいおじいちゃんのメソッドだろうと、
PHPの手にかかれば呼び出せてしまうわけです。
なお検証の結果、privateは呼び出せませんでしたがprotectedならば呼び出せるようです。
self::と書いて呼び出している個所がコンパイル時にクラス名に展開されるように、
parent::と書いて呼び出している個所も親クラス名に展開されるのでしょう。
親とか自分とかそういった考えではなく、指定したクラスに対して処理を行う....
きっとそんな仕様なのでしょう。他の言語がどうだかしりませんが。
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment