14

次のコードがあります(実際には、これが私の実際のコードです):

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

実行する$foobar = new FooBar; $foobar->foo()と表示されますfoo

PHP がオブジェクト コンテキストで静的メソッドを使用しようとするのはなぜですか? これを回避する方法はありますか?


OK、皆さんは私の問題を理解していませんでした。静的メソッドと非静的メソッドの違いとそれらの呼び出し方法を知っています。を呼び出すと$foobar->foo()、PHP が静的メソッドを実行しようとするのはなぜですか?


注: 私は PHP 5.4.4 を実行しています。エラーは に報告されてE_ALLいます。

4

3 に答える 3

19

静的メソッドを呼び出すには、次のものは使用しません。

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

追加の注意事項 -インスタンスで呼び出された場合でも、メソッドは常に静的コンテキストで実行されると思います。私が間違っていた場合でも、これについて修正していただければ幸いです。

于 2013-01-17T15:21:18.040 に答える
9

PHP は非常に寛容な言語であるため、オーバーロードによってこのデフォルトの動作を防ぎ、__callStaticリフレクションを使用してメソッド スコープを検証することができます。

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

http://php.net/ReflectionClass

于 2013-01-17T15:30:15.710 に答える
2

FooBar 宣言に関する詳細情報が必要になる場合があります。明らかに、1 つが静的メソッドでもう 1 つがインスタンス メソッドであっても、2 つのメソッド 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();
}
于 2016-06-21T11:36:45.830 に答える