PHP использует статические методы в контексте объекта

у меня есть следующий код (например, для реального, это мой реальный код):

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

когда я запускаю $foobar = new FooBar; $foobar->foo() Это показывает foo.

почему PHP пытается использовать статический метод в контексте объекта ? Есть ли способ избежать этого ?


хорошо, вы, ребята, не поняли мою проблему : я знаю различия между статическими и нестатическими методами и как их называть. В этом весь смысл, если я позову!--3-->, почему PHP пытается запустить статический метод ?


Примечание: я запускаю PHP 5.4.4, отчеты об ошибках в E_ALL.

3 ответов


чтобы вызвать статический метод, вы не используете:

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

вы называете

FooBar::foo();

руководство PHP говорит...

объявление свойств и методов класса статическими позволяет обращаться к ним без создания экземпляра класса. Свойство, объявленное как статический не может быть доступен с экземпляром объекта класса (хотя a статический метод может).

вот почему вы не можете вызвать метод экземпляра, даже хотя ты не собирался этого делать.

независимо от того, вызываете ли вы статический метод статически или на экземпляре, вы не можете получить доступ $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');
    }
  }
}

одно дополнительное Примечание-I верить что метод всегда выполняется в статическом контексте, даже если он вызывается на экземпляр. Я рад, что меня поправили,если я ошибаюсь.


поскольку 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();
}