PHP 후기 정적 바인딩 분석 및 적용에 대한 자세한 설명

亚连
풀어 주다: 2018-05-26 17:45:36
원래의
1050명이 탐색했습니다.

이 기사에는 PHP 후기 정적 바인딩 분석 및 응용과 관련된 지식 포인트가 요약되어 있습니다. 이에 관심이 있는 친구는 배울 수 있습니다.

기본 지식

1. 범위 결정 연산자(::)

  • 는 정적 멤버, 클래스 상수에 액세스하는 데 사용할 수 있으며 클래스의 속성과 메서드를 재정의하는 데에도 사용할 수 있습니다.

  • 세 가지 특수 키워드 self, parent 및 static은 클래스 정의 내의 해당 속성이나 메서드에 액세스하는 데 사용됩니다.

  • parent는 상위 클래스에서 재정의된 속성이나 메서드를 호출하는 데 사용됩니다(표시되는 경우 해당 클래스의 상위 클래스로 확인됩니다).

  • self는 이 클래스의 메서드나 속성을 호출하는 데 사용됩니다(표시되는 경우 해당 클래스로 구문 분석됩니다. $this와의 차이점에 유의하세요. $this는 현재 인스턴스화된 개체를 가리킵니다).

  • 하위 클래스가 상위 클래스의 메서드를 재정의하면 PHP는 상위 클래스의 재정의된 메서드를 호출하지 않습니다. 상위 클래스의 메소드 호출 여부는 하위 클래스에 따라 다릅니다.

2. PHP 커널은 클래스의 상속 구현을 "컴파일 단계"에 배치합니다.

<?php
class A{
 const H = &#39;A&#39;;

 const J = &#39;A&#39;;

 static function testSelf(){
  echo self::H; //在编译阶段就确定了 self解析为 A
 }
}

class B extends A{
 const H = "B";

 const J = &#39;B&#39;;

 static function testParent(){
  echo parent::J; //在编译阶段就确定了 parent解析为A
 }

 /* 若重写testSelf则能输出“B”, 且C::testSelf()也是输出“B”
 static function testSelf(){
  echo self::H;
 }
 */

}

class C extends B{
 const H = "C";

 const J = &#39;C&#39;;
}

B::testParent();
B::testSelf();

echo "\n";

C::testParent();
C::testSelf();
로그인 후 복사

실행 결과:

AA
AA


결론:

본인 : : 및 parent::가 특정 클래스 X의 정의에 나타나면 해당 클래스로 구문 분석됩니다.

3.Static(정적) 키워드

Function:

- 함수 본문의 변수를 수정하는 static 키워드는 정적 지역 변수를 정의하는 데 사용됩니다.
- 클래스 멤버 함수 및 멤버 변수를 수정할 때 정적 멤버를 선언하는 데 사용됩니다.
- (PHP5.3 이후) 범위 확인자(::) 이전에 정적 지연 바인딩을 나타내는 특수 클래스입니다.

예:

정적 지역 변수 정의(모양: 로컬 함수 내)

특징: 정적 변수는 지역 함수 범위에만 존재하지만, 프로그램 실행이 이 범위를 벗어나도 해당 값은 손실되지 않습니다.

<?php
function test()
{
 static $count = 0;

 $count++;
 echo $count;
 if ($count < 10) {
  test();
 }
 $count--;
}
로그인 후 복사

정적 메서드, 정적 속성 정의

a) 클래스 속성이나 메서드를 정적으로 선언하면 클래스를 인스턴스화하지 않고도 직접 액세스할 수 있습니다.

b) 정적 속성은 클래스의 인스턴스화된 개체를 통해 액세스할 수 없습니다(그러나 정적 메서드는 가능함).

c) 액세스 제어가 지정되지 않은 경우 속성과 메서드는 기본적으로 공개로 설정됩니다.

d) 정적 메서드에서는 개체 호출이 필요하지 않으므로 정적 메서드에서는 의사 변수 $this를 사용할 수 없습니다.

e) 개체는 -> 연산자를 통해 정적 속성에 액세스할 수 없습니다.

f) 비정적 메서드를 정적으로 호출하면 E_STRICT 수준 오류가 발생합니다.

g) 다른 모든 PHP 정적 변수와 마찬가지로 정적 속성은 표현식이 아닌 리터럴이나 상수로만 초기화할 수 있습니다. 따라서 정적 속성은 정수 또는 배열로 초기화될 수 있지만 다른 변수나 함수 반환 값으로 초기화될 수 없으며 개체를 가리킬 수도 없습니다.

a. 정적 메서드 예(표시 위치: 클래스 메서드 정의)

<?php
class Foo {
 public static function aStaticMethod() {
  // ...
 }
}

Foo::aStaticMethod();
$classname = &#39;Foo&#39;;
$classname::aStaticMethod(); // 自PHP 5.3.0后,可以通过变量引用类
?>
로그인 후 복사

b. 정적 속성 예(표시 위치: 클래스 속성 정의)

<?php
class Foo
{
 public static $my_static = &#39;foo&#39;;

 public function staticValue() {
  return self::$my_static; //self 即 FOO类
 }
}

class Bar extends Foo
{
 public function fooStatic() {
  return parent::$my_static; //parent 即 FOO类
 }
}

print Foo::$my_static . "\n";

$foo = new Foo();
print $foo->staticValue() . "\n";
print $foo->my_static . "\n";  // Undefined "Property" my_static 

print $foo::$my_static . "\n";
$classname = &#39;Foo&#39;;
print $classname::$my_static . "\n"; // As of PHP 5.3.0

print Bar::$my_static . "\n";
$bar = new Bar();
print $bar->fooStatic() . "\n";
?>
로그인 후 복사

c. 위치: 클래스 메소드에서 변수나 메소드를 수정하는 데 사용됨)

자세한 분석은 아래에서

late static 바인딩(late static 바인딩)

PHP 5.3.0부터 PHP에 late static 바인딩이라는 기능이 추가되었습니다. 상속 범위 내에서 정적으로 호출된 클래스를 참조하는 데 사용됩니다.

1. 전달된 통화 및 전달되지 않은 통화

전달된 통화:

는 self::, parent::, static:: 및 forward_static_call() 방식으로 이루어진 정적 호출을 의미합니다.

전달되지 않은 호출:

클래스 이름을 명시적으로 지정하는 정적 호출(예: Foo::foo())

비정적 호출(예: $foo->foo())

2 . Post-static 바인딩 작동 방식

원리: 이전 "비전달 호출"의 클래스 이름이 저장됩니다. 이는 순방향 호출인 정적 호출을 호출할 때 실제로 호출되는 클래스가 이전 비전달 호출의 클래스라는 것을 의미합니다.

예제 분석:

<?php
class A {
 public static function foo() {
  echo __CLASS__."\n";
  static::who();
 }

 public static function who() {
  echo __CLASS__."\n";
 }
}

class B extends A {
 public static function test() {
  echo "A::foo()\n";
  A::foo();
  echo "parent::foo()\n";
  parent::foo();
  echo "self::foo()\n";
  self::foo();
 }

 public static function who() {
  echo __CLASS__."\n";
 }
}

class C extends B {
 public static function who() {
  echo __CLASS__."\n";
 }
}

C::test();

/*
 * C::test(); //非转发调用 ,进入test()调用后,“上一次非转发调用”存储的类名为C
 *
 * //当前的“上一次非转发调用”存储的类名为C
 * public static function test() {
 *  A::foo(); //非转发调用, 进入foo()调用后,“上一次非转发调用”存储的类名为A,然后实际执行代码A::foo(), 转 0-0
 *  parent::foo(); //转发调用, 进入foo()调用后,“上一次非转发调用”存储的类名为C, 此处的parent解析为A ,转1-0
 *  self::foo(); //转发调用, 进入foo()调用后,“上一次非转发调用”存储的类名为C, 此处self解析为B, 转2-0
 * }
 *
 *
 * 0-0
 * //当前的“上一次非转发调用”存储的类名为A
 * public static function foo() {
 *  static::who(); //转发调用, 因为当前的“上一次非转发调用”存储的类名为A, 故实际执行代码A::who(),即static代表A,进入who()调用后,“上一次非转发调用”存储的类名依然为A,因此打印 “A”
 * }
 *
 * 1-0
 * //当前的“上一次非转发调用”存储的类名为C
 * public static function foo() {
 *  static::who(); //转发调用, 因为当前的“上一次非转发调用”存储的类名为C, 故实际执行代码C::who(),即static代表C,进入who()调用后,“上一次非转发调用”存储的类名依然为C,因此打印 “C”

 * }
 *
 * 2-0
 * //当前的“上一次非转发调用”存储的类名为C
 * public static function foo() {
 *  static::who(); //转发调用, 因为当前的“上一次非转发调用”存储的类名为C, 故实际执行代码C::who(),即static代表C,进入who()调用后,“上一次非转发调用”存储的类名依然为C,因此打印 “C”
 * }
 */


故最终结果为:
A::foo()
A
A
parent::foo()
A
C
self::foo()
A
C
로그인 후 복사

3. 정적 후기 정적 바인딩의 추가 예

a) Self, Parent 및 Static 비교

<?php
class Mango {
 function classname(){
  return __CLASS__;
 }

 function selfname(){
  return self::classname();
 }

 function staticname(){
  return static::classname();
 }
}

class Orange extends Mango {
 function parentname(){
  return parent::classname();
 }

 function classname(){
  return __CLASS__;
 }
}

class Apple extends Orange {
 function parentname(){
  return parent::classname();
 }

 function classname(){
  return __CLASS__;
 }
}

$apple = new Apple();
echo $apple->selfname() . "\n";
echo $apple->parentname() . "\n";
echo $apple->staticname();

?>

运行结果:
Mango
Orange
Apple
로그인 후 복사

b) 사용

<?php
class Mango
{
 const NAME = &#39;Mango is&#39;;
 public static function fruit() {
  $args = func_get_args();
  echo static::NAME, " " . join(&#39; &#39;, $args) . "\n";
 }
}

class Orange extends Mango
{
 const NAME = &#39;Orange is&#39;;

 public static function fruit() {
  echo self::NAME, "\n";

  forward_static_call(array(&#39;Mango&#39;, &#39;fruit&#39;), &#39;my&#39;, &#39;favorite&#39;, &#39;fruit&#39;);
  forward_static_call(&#39;fruit&#39;, &#39;my&#39;, &#39;father\&#39;s&#39;, &#39;favorite&#39;, &#39;fruit&#39;);
 }
}

Orange::fruit(&#39;NO&#39;);

function fruit() {
 $args = func_get_args();
 echo "Apple is " . join(&#39; &#39;, $args). "\n";
}

?>


运行结果:
Orange is
Orange is my favorite fruit
Apple is my father&#39;s favorite fruit
로그인 후 복사

c) get_called_class() 사용

<?php


class Mango {
 static public function fruit() {
  echo get_called_class() . "\n";
 }
}

class Orange extends Mango {
 //
}

Mango::fruit();
Orange::fruit();

?>



运行结果:
Mango
Orange
로그인 후 복사

Application

앞서 언급했듯이 후기 정적 바인딩을 도입하는 목적은 다음과 같습니다. 상속 범위의 정적 참조 호출 클래스.
따라서 후기 정적 바인딩을 사용하여 싱글톤 상속 문제를 해결할 수 있습니다.

먼저 self를 사용하는 것이 어떤 것인지 살펴보겠습니다.

<?php
// new self 得到的单例都为A。
class A
{
 protected static $_instance = null;

 protected function __construct()
 {
  //disallow new instance
 }

 protected function __clone(){
  //disallow clone
 }

 static public function getInstance()
 {
  if (self::$_instance === null) {
   self::$_instance = new self();
  }
  return self::$_instance;
 }
}

class B extends A
{
 protected static $_instance = null;
}

class C extends A{
 protected static $_instance = null;
}

$a = A::getInstance();
$b = B::getInstance();
$c = C::getInstance();

var_dump($a);
var_dump($b);
var_dump($c);




运行结果:
E:\code\php_test\apply\self.php:37:
class A#1 (0) {
}
E:\code\php_test\apply\self.php:38:
class A#1 (0) {
}
E:\code\php_test\apply\self.php:39:
class A#1 (0) {
}
로그인 후 복사

위의 예에서 볼 수 있듯이 self를 사용하면 인스턴스화된 모든 객체는 클래스 A의 동일한 객체입니다.

하자 어떻게 사용하는지 살펴보세요. static은 어떤 결과를 얻을까요?

<?php
// new static 得到的单例分别为D,E和F。
class D
{
 protected static $_instance = null;

 protected function __construct(){}
 protected function __clone()
 {
  //disallow clone
 }

 static public function getInstance()
 {
  if (static::$_instance === null) {
   static::$_instance = new static();
  }
  return static::$_instance;
 }
}

class E extends D
{
 protected static $_instance = null;
}

class F extends D{
 protected static $_instance = null;
}

$d = D::getInstance();
$e = E::getInstance();
$f = F::getInstance();

var_dump($d);
var_dump($e);
var_dump($f);




运行结果:
E:\code\php_test\apply\static.php:35:
class D#1 (0) {
}
E:\code\php_test\apply\static.php:36:
class E#2 (0) {
}
E:\code\php_test\apply\static.php:37:
class F#3 (0) {
}
로그인 후 복사

위 내용은 제가 모두를 위해 정리한 내용입니다. 앞으로 모든 사람에게 도움이 되기를 바랍니다.

관련 기사:

AjaxSubmit()은 파일을 제출합니다

Ajax가 불필요한 새로 고침을 해결하는 두 가지 방법

Ajax 동기화 및 비동기 문제 분석 및 솔루션

위 내용은 PHP 후기 정적 바인딩 분석 및 적용에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!