Подтвердить что ты не робот

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

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

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

Когда я запустил $foobar = new FooBar; $foobar->foo(), он отображает foo.

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


Хорошо, вы, ребята, не получили мою проблему: я знаю различия между статическими и нестационарными методами и как их называть. Что все-таки, если я называю $foobar->foo(), почему PHP пытается запустить статический метод?


Примечание. Я запускаю PHP 5.4.4, сообщение об ошибках E_ALL.

4b9b3361

Ответ 1

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

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

Вы вызываете

FooBar::foo();

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

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

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

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

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

Ответ 3

Нам может понадобиться дополнительная информация о объявлении 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 do some kind of magic
  echo $foobar->foo();
}

Ответ 4

Не используйте static method в object context объекта, сначала получите класс из объекта.

class a {
    public static function myStaticFunction(){
        return 'qwer';
    }

    public function getClass(){
        return get_class($this);
    }
}

$a = new a();
echo $a->getClass()::myStaticFunction();

Но подумайте дважды, может быть, вам на самом деле не нужна static function и вы можете хорошо использовать const, потому что это то, что вы можете получить от объекта:

class a {
    const MY_CONST = 123;
}

$a = new a();
echo $a::MY_CONST;