我有以下代码(如,真的,这是我真正的代码):
<?php
class Foobar
{
public static function foo()
{
exit('foo');
}
}
当我运行$foobar = new FooBar; $foobar->foo()
$foobar = new FooBar; $foobar->foo()
它显示foo
。
为什么PHP会在对象上下文中使用一个静态方法? 是否有办法避免这种情况?
好吧,你们没得到我的问题:我知道静态和非静态方法和如何调用它们之间的差异。 这是我的整点,如果我叫$foobar->foo()
为什么PHP试图运行一个静态方法?
注:我运行PHP 5.4.4,错误报告E_ALL
。
要调用一个静态方法,您不使用:
$foobar = new FooBar;
$foobar->foo()
你叫
FooBar::foo();
PHP手册说...
声明类属性或方法为静态,使他们无需类的实例访问。 声明为静态属性不能与实例化的类对象(尽管一个静态方法可以)进行访问。
这就是为什么你可以致电实例的方法,尽管这是不是你打算做。
无论你是否调用静态方法静态或实例,您无法访问$this
在静态方法。
http://php.net/manual/en/language.oop5.static.php
你可以检查一下,如果你在一个静态的背景下,虽然我怀疑这是否是矫枉过正...
class Foobar
{
public static function foo()
{
$backtrace = debug_backtrace();
if ($backtrace[1]['type'] == '::') {
exit('foo');
}
}
}
另外也请注意-我相信 ,该方法是在静态情况下总是执行,即使它被称为上的一个实例。 我很高兴,如果我错了,虽然要在此更正。
由于PHP是一个相当宽容的语言,你可以阻止这种默认行为,通过超载__callStatic
,也许使用反射来验证方法的范围。
http://php.net/manual/en/language.oop5.overloading.php#object.call
http://php.net/ReflectionClass
我们可能需要对FooBar的声明更多的信息。 很显然,你不能声明两种方法FOO(),即使一个是一个静态方法,另一个实例方法:
class FooBar
{
public static function foo()
{
return 'I am FooBar::foo().';
}
public function foo()
{
return 'I am FooBar->foo().';
}
}
// result to Fatal error: Cannot redeclare FooBar::foo()
所以,我想,你想达到一个神奇的__call()
方法,像这样:
class FooBar
{
public $foo = 'I am FooBar->foo().';
// yes we can have a property with the same name than a method
// this is the static method that we want to avoid
public static function foo()
{
return 'I am FooBar::foo().';
}
// this is the method that should be call
public function __call( $method , $arguments = array() )
{
if( isset( $this->$method ) ) // or anything else
{
return $this->$method; // or anything else
}
else
{
// restore fatal error
trigger_error( sprintf( 'Call to undefined method %s::%s()' , get_class( $this ) , $method ) , E_USER_ERROR );
}
}
}
为了实现这一目标,看这一段代码:
$foobar = new FooBar;
try
{
// safe way to detect if a method is static
// @see http://php.net/manual/en/class.reflectionmethod.php
$rfx = new ReflectionMethod( get_class( $foobar ).'::foo' );
if( $rfx->isStatic() )
{
// the method exists and is static
// but we do not want to call it directly
// why not involving the magic public method `__call()`?
// sounds like a plan...
echo $foobar->__call( 'foo' );
}
else
{
// the method exists and is not static
echo $foobar->foo();
}
}
catch( ReflectionException $e )
{
// the method does not exist, let's do some kind of magic
echo $foobar->foo();
}