Why PHP uses static methods in object context?

放肆的年华 提交于 2019-11-29 17:14:01

问题


I have the following code (like, for real, this is my real code) :

<?php
class Foobar
{
  public static function foo()
  {
    exit('foo');
  }
}

When I run $foobar = new FooBar; $foobar->foo() it displays foo.

Why would PHP try to use a static method in an object context ? Is there a way to avoid this ?


Ok you guys didn't get my problem : I know the differences between static and non static methods and how to call them. That's my whole point, if I call $foobar->foo(), why does PHP tries to run a static method ?


Note : I run PHP 5.4.4, error reporting to E_ALL.


回答1:


To call a static method, you don't use:

$foobar = new FooBar;
$foobar->foo()

You call

FooBar::foo();

The PHP manual says...

Declaring class properties or methods as static makes them accessible without needing an instantiation of the class. A property declared as static can not be accessed with an instantiated class object (though a static method can).

This is why you are able to call the method on an instance, even though that is not what you intended to do.

Whether or not you call a static method statically or on an instance, you cannot access $this in a static method.

http://php.net/manual/en/language.oop5.static.php

You can check to see if you are in a static context, although I would question whether this is overkill...

class Foobar
{
  public static function foo()
  {
    $backtrace = debug_backtrace();
    if ($backtrace[1]['type'] == '::') {
      exit('foo');
    }
  }
}

One additional note - I believe that the method is always executed in a static context, even if it is called on an instance. I'm happy to be corrected on this if I'm wrong though.




回答2:


Since PHP is quite a forgiving language you could prevent this default behavior by overloading __callStatic and maybe use reflections to validate the method scope.

http://php.net/manual/en/language.oop5.overloading.php#object.call

http://php.net/ReflectionClass




回答3:


We may need more information about the FooBar declaration. Obviously, you cannot declare two methods foo() even if one is a static method and the other one an instance method:

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()

So, I suppose that you want to reach a magic __call() method, like so:

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 );
    }
  }

}

To achieve that, look at this piece of code:

$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();
}


来源:https://stackoverflow.com/questions/14382206/why-php-uses-static-methods-in-object-context

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!