최근에 "php Core Technology and Best Practices"라는 책을 읽고 있습니다. 이 책의 첫 번째 장에서는 __call() 메서드를 사용하여 간단한 문자열 체인 작업을 구현할 수 있다고 언급하고 있습니다. 그런 다음 길이를 찾으려면 일반적으로 다음과 같이 작업을 작성합니다.
<span style="color: #008080;">strlen</span>(<span style="color: #008080;">trim</span>(<span style="color: #800080;">$str</span>));
그러면 다음과 같은 작성 방법을 구현하는 것이 가능한가요?
<span style="color: #800080;">$str</span>-><span style="color: #008080;">trim</span>()-><span style="color: #008080;">strlen</span>();
한번 해보세요.
체인 연산은 직설적으로 말하면 실제로는 체인의 객체를 호출하는 방법입니다. 문자열 체인 작업을 구현하려면 문자열 클래스를 구현한 다음 이 클래스의 개체를 호출해야 합니다. 문자열 클래스에 대한 기대치는 다음과 같습니다. (1) 객체를 생성할 때 문자열을 객체의 속성에 할당할 수 있으며 이 속성에 액세스하여 값을 읽을 수 있습니다. (2) Trim( ) 및 strlen( ) 메서드; (3) $str->trim()->strlen() 메서드를 이와 같이 호출할 수도 있습니다.
위의 (1) 항목은 문자열 클래스의 기본 요구 사항입니다. 먼저 이를 구현해 보겠습니다.
<span style="color: #008080;">1</span> <span style="color: #0000ff;">class</span> <span style="color: #0000ff;">String</span> <span style="color: #008080;">2</span> <span style="color: #000000;">{ </span><span style="color: #008080;">3</span> <span style="color: #0000ff;">public</span> <span style="color: #800080;">$value</span><span style="color: #000000;">; </span><span style="color: #008080;">4</span> <span style="color: #008080;">5</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> __construct(<span style="color: #800080;">$str</span>=<span style="color: #0000ff;">null</span><span style="color: #000000;">) </span><span style="color: #008080;">6</span> <span style="color: #000000;"> { </span><span style="color: #008080;">7</span> <span style="color: #800080;">$this</span>->value = <span style="color: #800080;">$str</span><span style="color: #000000;">; </span><span style="color: #008080;">8</span> <span style="color: #000000;"> } </span><span style="color: #008080;">9</span> }
다음을 시도해 보세요.
<span style="color: #008080;">1</span> <span style="color: #800080;">$str</span> = <span style="color: #0000ff;">new</span> <span style="color: #0000ff;">String</span>('01389'<span style="color: #000000;">); </span><span style="color: #008080;">2</span> <span style="color: #0000ff;">echo</span> <span style="color: #800080;">$str</span>->value;
그런 다음 항목 2를 살펴보고 먼저 $str->trim()을 구현하고 책의 아이디어를 참조하세요. __call 메서드를 트리거한 다음 call_user_func를 실행하세요. 코드는 다음과 같습니다.
<span style="color: #008080;"> 1</span> <span style="color: #0000ff;">class</span> <span style="color: #0000ff;">String</span> <span style="color: #008080;"> 2</span> <span style="color: #000000;">{ </span><span style="color: #008080;"> 3</span> <span style="color: #0000ff;">public</span> <span style="color: #800080;">$value</span><span style="color: #000000;">; </span><span style="color: #008080;"> 4</span> <span style="color: #008080;"> 5</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> __construct(<span style="color: #800080;">$str</span>=<span style="color: #0000ff;">null</span><span style="color: #000000;">) </span><span style="color: #008080;"> 6</span> <span style="color: #000000;"> { </span><span style="color: #008080;"> 7</span> <span style="color: #800080;">$this</span>->value = <span style="color: #800080;">$str</span><span style="color: #000000;">; </span><span style="color: #008080;"> 8</span> <span style="color: #000000;"> } </span><span style="color: #008080;"> 9</span> <span style="color: #008080;">10</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> __call(<span style="color: #800080;">$name</span>, <span style="color: #800080;">$args</span><span style="color: #000000;">) </span><span style="color: #008080;">11</span> <span style="color: #000000;"> { </span><span style="color: #008080;">12</span> <span style="color: #800080;">$this</span>->value = <span style="color: #008080;">call_user_func</span>(<span style="color: #800080;">$name</span>, <span style="color: #800080;">$this</span>->value, <span style="color: #800080;">$args</span>[0<span style="color: #000000;">]); </span><span style="color: #008080;">13</span> <span style="color: #0000ff;">return</span> <span style="color: #800080;">$this</span><span style="color: #000000;">; </span><span style="color: #008080;">14</span> <span style="color: #000000;"> } </span><span style="color: #008080;">15</span> }
테스트 중:
<span style="color: #008080;">1</span> <span style="color: #800080;">$str</span> = <span style="color: #0000ff;">new</span> <span style="color: #0000ff;">String</span>('01389'<span style="color: #000000;">); </span><span style="color: #008080;">2</span> <span style="color: #0000ff;">echo</span> <span style="color: #800080;">$str</span>-><span style="color: #008080;">trim</span>('0')->value;
결과는 다음과 같습니다.
위에서 주목해야 할 것은 라인 12입니다: $this->value = call_user_func($name, $ this ->value, $args[0]); $name은 콜백 함수의 이름(여기서는 트림)이고 마지막 두 개는 콜백의 매개변수입니다. 함수(tirm). 매개변수의 순서를 바꾸지 마십시오. $args는 배열이므로 주의가 필요합니다.
Strlen()은 Article 2에서도 구현되어야 합니다. 이때 위 코드의 13행이 중요합니다. return $this; 함수는 문자열을 처리하기 위해 12행에서 Trim()을 호출한 후 값 속성을 다시 할당한 다음 현재 개체의 참조를 반환하여 개체의 다른 메서드가 속성 값에 대해 계속해서 작동할 수 있도록 하는 것입니다. 작업. $str->strlen()은 다음과 같이 구현됩니다:
<span style="color: #008080;"> 1</span> <span style="color: #0000ff;">class</span> <span style="color: #0000ff;">String</span> <span style="color: #008080;"> 2</span> <span style="color: #000000;">{ </span><span style="color: #008080;"> 3</span> <span style="color: #0000ff;">public</span> <span style="color: #800080;">$value</span><span style="color: #000000;">; </span><span style="color: #008080;"> 4</span> <span style="color: #008080;"> 5</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> __construct(<span style="color: #800080;">$str</span>=<span style="color: #0000ff;">null</span><span style="color: #000000;">) </span><span style="color: #008080;"> 6</span> <span style="color: #000000;"> { </span><span style="color: #008080;"> 7</span> <span style="color: #800080;">$this</span>->value = <span style="color: #800080;">$str</span><span style="color: #000000;">; </span><span style="color: #008080;"> 8</span> <span style="color: #000000;"> } </span><span style="color: #008080;"> 9</span> <span style="color: #008080;">10</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> __call(<span style="color: #800080;">$name</span>, <span style="color: #800080;">$args</span><span style="color: #000000;">) </span><span style="color: #008080;">11</span> <span style="color: #000000;"> { </span><span style="color: #008080;">12</span> <span style="color: #800080;">$this</span>->value = <span style="color: #008080;">call_user_func</span>(<span style="color: #800080;">$name</span>, <span style="color: #800080;">$this</span>->value, <span style="color: #800080;">$args</span>[0<span style="color: #000000;">]); </span><span style="color: #008080;">13</span> <span style="color: #0000ff;">return</span> <span style="color: #800080;">$this</span><span style="color: #000000;">; </span><span style="color: #008080;">14</span> <span style="color: #000000;"> } </span><span style="color: #008080;">15</span> <span style="color: #008080;">16</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> <span style="color: #008080;">strlen</span><span style="color: #000000;">() </span><span style="color: #008080;">17</span> <span style="color: #000000;"> { </span><span style="color: #008080;">18</span> <span style="color: #0000ff;">return</span> <span style="color: #008080;">strlen</span>(<span style="color: #800080;">$this</span>-><span style="color: #000000;">value); </span><span style="color: #008080;">19</span> <span style="color: #000000;"> } </span><span style="color: #008080;">20</span> }
테스트 중:
<span style="color: #008080;">1</span> <span style="color: #800080;">$str</span> = <span style="color: #0000ff;">new</span> <span style="color: #0000ff;">String</span>('01389'<span style="color: #000000;">); </span><span style="color: #008080;">2</span> <span style="color: #0000ff;">echo</span> <span style="color: #800080;">$str</span>-><span style="color: #008080;">strlen</span>();
결과:
체인 운영:
<span style="color: #0000ff;">echo</span> <span style="color: #800080;">$str</span>-><span style="color: #008080;">trim</span>('0')-><span style="color: #008080;">strlen</span>();
결과:
이 시점에서 이 글은 끝났어야 했습니다. 그런데 곰곰이 생각해 보니 __call() 메서드를 사용하지 않고도 체인 작업을 수행할 수 있다는 것을 알게 되었습니다. 다음은 __call()을 사용하지 않은 구현입니다.
<span style="color: #008080;"> 1</span> <span style="color: #0000ff;">class</span> <span style="color: #0000ff;">String</span> <span style="color: #008080;"> 2</span> <span style="color: #000000;">{ </span><span style="color: #008080;"> 3</span> <span style="color: #0000ff;">public</span> <span style="color: #800080;">$value</span><span style="color: #000000;">; </span><span style="color: #008080;"> 4</span> <span style="color: #008080;"> 5</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> __construct(<span style="color: #800080;">$str</span>=<span style="color: #0000ff;">null</span><span style="color: #000000;">) </span><span style="color: #008080;"> 6</span> <span style="color: #000000;"> { </span><span style="color: #008080;"> 7</span> <span style="color: #800080;">$this</span>->value = <span style="color: #800080;">$str</span><span style="color: #000000;">; </span><span style="color: #008080;"> 8</span> <span style="color: #000000;"> } </span><span style="color: #008080;"> 9</span> <span style="color: #008080;">10</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> <span style="color: #008080;">trim</span>(<span style="color: #800080;">$t</span><span style="color: #000000;">) </span><span style="color: #008080;">11</span> <span style="color: #000000;"> { </span><span style="color: #008080;">12</span> <span style="color: #800080;">$this</span>->value = <span style="color: #008080;">trim</span>(<span style="color: #800080;">$this</span>->value, <span style="color: #800080;">$t</span><span style="color: #000000;">); </span><span style="color: #008080;">13</span> <span style="color: #0000ff;">return</span> <span style="color: #800080;">$this</span><span style="color: #000000;">; </span><span style="color: #008080;">14</span> <span style="color: #000000;"> } </span><span style="color: #008080;">15</span> <span style="color: #008080;">16</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> <span style="color: #008080;">strlen</span><span style="color: #000000;">() </span><span style="color: #008080;">17</span> <span style="color: #000000;"> { </span><span style="color: #008080;">18</span> <span style="color: #0000ff;">return</span> <span style="color: #008080;">strlen</span>(<span style="color: #800080;">$this</span>-><span style="color: #000000;">value); </span><span style="color: #008080;">19</span> <span style="color: #000000;"> } </span><span style="color: #008080;">20</span> }
연쇄 작업의 핵심은 작업 완료 후 $this를 반환하는 것입니다.
또한 이 글은 Garden의 이 글에서 영감을 받아 call_user_func() 구현을 call_user_func_array()로 대체하고 __call() 메서드를 다음과 같이 수정했습니다.
<span style="color: #008080;">1</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> __call(<span style="color: #800080;">$name</span>, <span style="color: #800080;">$args</span><span style="color: #000000;">) </span><span style="color: #008080;">2</span> <span style="color: #000000;"> { </span><span style="color: #008080;">3</span> <span style="color: #008080;">array_unshift</span>(<span style="color: #800080;">$args</span>, <span style="color: #800080;">$this</span>-><span style="color: #000000;">value); </span><span style="color: #008080;">4</span> <span style="color: #800080;">$this</span>->value = <span style="color: #008080;">call_user_func_array</span>(<span style="color: #800080;">$name</span>, <span style="color: #800080;">$args</span><span style="color: #000000;">); </span><span style="color: #008080;">5</span> <span style="color: #0000ff;">return</span> <span style="color: #800080;">$this</span><span style="color: #000000;">; </span><span style="color: #008080;">6</span> }
위의 __call() 메서드와 효과가 동일해서 이전 구현보다 코드가 더 우아해진 것 같습니다.
요약:
__call()은 객체가 액세스할 수 없는 메소드를 호출할 때 트리거되므로 클래스의 동적 메소드 생성을 실현하고 PHP의 메소드 오버로딩 기능을 실현할 수 있지만 실제로는 구문 설탕입니다(__construct() 방법도 )입니다.
그러면 __call()과 같은 구문 설탕이 없다면 동적 메서드의 생성과 연결이 실현될 수 있을까요? 나는 다음과 같은 측면을 포함할 것이라고 생각합니다: 클래스 메소드가 존재하는지, 호출될 수 있는지. 이는 method_exists, is_callable, get_class_methods 및 기타 메소드를 사용하여 달성할 수 있습니다. 또한 객체를 생성할 때 속성에 값(초기화)을 할당하는 것은 실제로 편리하지만 꼭 필요한 것은 아닙니다. 시간 나면 다시 공부해 봅시다.