PHP 클래스 생성자가 부모의 부모 생성자를 호출하도록하려면 어떻게해야합니까?
PHP에서 클래스 생성자가 부모 생성자를 호출하지 않고 부모의 부모 (조부모?) 생성자를 호출해야합니다.
// main class that everything inherits
class Grandpa
{
public function __construct()
{
}
}
class Papa extends Grandpa
{
public function __construct()
{
// call Grandpa's constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
// THIS IS WHERE I NEED TO CALL GRANDPA'S
// CONSTRUCTOR AND NOT PAPA'S
}
}
나는 이것이 기괴한 일이라는 것을 알고 있으며, 나쁘지 않지만 냄새가 나는 방법을 찾으려고 노력하고 있습니다. 가능하다면 궁금합니다.
추악한 해결 방법은 부울 매개 변수를 Papa에 전달하여 생성자에 포함 된 코드를 구문 분석하지 않으려는 것을 나타냅니다. 즉 :
// main class that everything inherits
class Grandpa
{
public function __construct()
{
}
}
class Papa extends Grandpa
{
public function __construct($bypass = false)
{
// only perform actions inside if not bypassing
if (!$bypass) {
}
// call Grandpa's constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
$bypassPapa = true;
parent::__construct($bypassPapa);
}
}
를 사용해야 Grandpa::__construct()
합니다. 다른 단축키는 없습니다. 또한 이것은 Papa
클래스 의 캡슐화를 망칩니다 -읽거나 작업 할 때 메소드가 생성 중에 호출 될 Papa
것이라고 가정하는 것이 안전해야 __construct()
하지만 Kiddo
클래스는 이것을하지 않습니다.
class Grandpa
{
public function __construct()
{}
}
class Papa extends Grandpa
{
public function __construct()
{
//call Grandpa's constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
//this is not a bug, it works that way in php
Grandpa::__construct();
}
}
를 사용하는 아름다운 솔루션 Reflection
.
<?php
class Grandpa
{
public function __construct()
{
echo "Grandpa's constructor called\n";
}
}
class Papa extends Grandpa
{
public function __construct()
{
echo "Papa's constructor called\n";
// call Grandpa's constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
echo "Kiddo's constructor called\n";
$reflectionMethod = new ReflectionMethod(get_parent_class(get_parent_class($this)), '__construct');
$reflectionMethod->invoke($this);
}
}
$kiddo = new Kiddo();
$papa = new Papa();
결국 문제를 해결 한 대체 솔루션을 찾았습니다.
- 할아버지를 확장하는 중급 클래스를 만들었습니다.
- 그런 다음 Papa와 Kiddo는 모두 그 수업을 확장했습니다.
- Kiddo는 Papa의 중간 기능이 필요했지만 생성자가 마음에 들지 않아 클래스에 추가 기능이 있으며 둘 다 확장했습니다.
나는 추악한 질문에 대해 유효하지만 추악한 해결책을 제공하는 다른 두 가지 대답을 찬성했습니다.)
플래그를 사용하지 않고 상황에 따라 작동하는 다른 옵션 :
<?php
// main class that everything inherits
class Grandpa
{
public function __construct(){
$this->GrandpaSetup();
}
public function GrandpaSetup(){
$this->prop1 = 'foo';
$this->prop2 = 'bar';
}
}
class Papa extends Grandpa
{
public function __construct()
{
// call Grandpa's constructor
parent::__construct();
$this->prop1 = 'foobar';
}
}
class Kiddo extends Papa
{
public function __construct()
{
$this->GrandpaSetup();
}
}
$kid = new Kiddo();
echo "{$kid->prop1}\n{$kid->prop2}\n";
"너무 많은 PHP"에 동의합니다.
class Grandpa
{
public function __construct()
{
echo 'Grandpa<br/>';
}
}
class Papa extends Grandpa
{
public function __construct()
{
echo 'Papa<br/>';
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
// THIS IS WHERE I NEED TO CALL GRANDPA'S
// CONSTRUCTOR AND NOT PAPA'S
echo 'Kiddo<br/>';
Grandpa::__construct();
}
}
$instance = new Kiddo;
예상대로 결과를 얻었습니다.
키도
할아버지
이것은 버그가 아닌 기능이므로 참조를 위해 확인하십시오.
https://bugs.php.net/bug.php?id=42016
그것은 작동하는 방식입니다. 올바른 컨텍스트에서 오는 것으로 확인되면이 호출 버전은 정적 호출을 시행하지 않습니다.
대신 단순히 $ this를 유지하고 만족합니다.
parent :: method ()는 동일한 방식으로 작동하므로 메소드를 정적으로 정의 할 필요는 없지만 동일한 컨텍스트에서 호출 할 수 있습니다. 더 흥미롭게 이것을 시도하십시오 :
class Grandpa
{
public function __construct()
{
echo 'Grandpa<br/>';
Kiddo::hello();
}
}
class Papa extends Grandpa
{
public function __construct()
{
echo 'Papa<br/>';
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
// THIS IS WHERE I NEED TO CALL GRANDPA'S
// CONSTRUCTOR AND NOT PAPA'S
echo 'Kiddo<br/>';
Grandpa::__construct();
}
public function hello()
{
echo 'Hello<br/>';
}
}
$instance = new Kiddo;
예상대로 작동합니다.
키도
할아버지
여보세요
그러나 새 Papa를 초기화하려고하면 E_STRICT 오류가 발생합니다.
$papa = new Papa;
엄격한 표준 : 비 정적 메소드 Kiddo :: hello ()는 $ this를 호환되지 않는 컨텍스트에서 가정하면 정적으로 호출해서는 안됩니다.
instanceof를 사용하여 부모 메서드에서 Children :: method ()를 호출 할 수 있는지 확인할 수 있습니다.
if ($this instanceof Kiddo) Kiddo::hello();
더 쉬운 해결책이 있지만 현재 클래스가 얼마나 많은 상속을 받았는지 정확하게 알아야합니다. 다행스럽게도 get_parent_class ()의 인수를 사용하면 클래스 배열 멤버가 인스턴스뿐만 아니라 문자열의 클래스 이름이 될 수 있습니다.
상속하는 객체의 인스턴스 범위 내 에서이 특별한 경우의 차이는 무시할 수 있지만 (ah, PHP), 이것은 본질적으로 클래스의 __construct () 메소드를 정적으로 호출하는 것에 의존한다는 것을 명심하십시오.
다음을 고려하세요:
class Foo {
var $f = 'bad (Foo)';
function __construct() {
$this->f = 'Good!';
}
}
class Bar extends Foo {
var $f = 'bad (Bar)';
}
class FooBar extends Bar {
var $f = 'bad (FooBar)';
function __construct() {
# FooBar constructor logic here
call_user_func(array(get_parent_class(get_parent_class($this)), '__construct'));
}
}
$foo = new FooBar();
echo $foo->f; #=> 'Good!'
다시 말하지만, 이것은 debug_backtrace ()의 한계로 인해 얼마나 많은 상속이 발생했는지 알지 못하는 상황에서는 실행 가능한 솔루션이 아니지만 통제 된 환경에서는 의도 한대로 작동합니다.
원하는 곳에서 Grandpa :: __ construct를 호출하면 $ this 키워드가 현재 클래스 인스턴스를 참조합니다.
그러나이 방법을 사용하면이 다른 컨텍스트에서 현재 인스턴스의 보호 된 속성 및 메서드에 액세스 할 수 없으며 공용 요소에만 액세스 할 수 없습니다.
=> 모든 업무와 공식 지원 .
예
// main class that everything inherits
class Grandpa
{
public function __construct()
{
echo $this->one; // will print 1
echo $this->two; // error cannot access protected property
}
}
class Papa extends Grandpa
{
public function __construct()
{
// call Grandpa's constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public $one = 1;
protected $two = 2;
public function __construct()
{
Grandpa::__construct();
}
}
new Kiddo();
PHP에 대한 재미있는 세부 사항 : 확장 클래스는 정적 문제에서 부모 클래스의 비 정적 함수를 사용할 수 있습니다. 외부에서는 엄격한 오류가 발생합니다.
error_reporting(E_ALL);
class GrandPa
{
public function __construct()
{
print("construct grandpa<br/>");
$this->grandPaFkt();
}
protected function grandPaFkt(){
print(">>do Grandpa<br/>");
}
}
class Pa extends GrandPa
{
public function __construct()
{ parent::__construct();
print("construct Pa <br/>");
}
public function paFkt(){
print(">>do Pa <br>");
}
}
class Child extends Pa
{
public function __construct()
{
GrandPa::__construct();
Pa::paFkt();//allright
//parent::__construct();//whatever you want
print("construct Child<br/>");
}
}
$test=new Child();
$test::paFkt();//strict error
확장 클래스 (자식) 안에서 사용할 수 있습니다.
parent::paFkt();
또는
Pa::paFkt();
부모 (또는 할아버지) (비공개) 기능에 액세스합니다.
외부 클래스 데프
$test::paFkt();
엄격한 오류가 발생하지 않습니다 (정적 기능이 아님).
좋아, 또 다른 추악한 해결책 :
Papa에서 다음과 같은 함수를 작성하십시오.
protected function call2Granpa() {
return parent::__construct();
}
그런 다음 Kiddo에서 다음을 사용합니다.
parent::call2Granpa();
// Papa에서 생성자를 호출하는 대신.
나는 그것이 효과가 있다고 생각합니다 ... 테스트하지 않았으므로 객체가 올바르게 생성되었는지 확실하지 않습니다.
이 접근 방식을 사용했지만 생성자가 아닌 함수를 사용했습니다.
<?php
class grand_pa
{
public function __construct()
{
echo "Hey I am Grand Pa <br>";
}
}
class pa_pa extends grand_pa
{
// no need for construct here unless you want to do something specifically within this class as init stuff
// the construct for this class will be inherited from the parent.
}
class kiddo extends pa_pa
{
public function __construct()
{
parent::__construct();
echo "Hey I am a child <br>";
}
}
new kiddo();
?>
물론 이것은 pa_pa의 구조 내에서 아무것도 할 필요가 없습니다. 이것을 실행하면 다음이 출력됩니다.
안녕하세요, Grand Pa입니다 안녕하세요, 저는 아이입니다
// main class that everything inherits
class Grandpa
{
public function __construct()
{
$this->___construct();
}
protected function ___construct()
{
// grandpa's logic
}
}
class Papa extends Grandpa
{
public function __construct()
{
// call Grandpa's constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
parent::___construct();
}
}
"___construct"는 마법 이름이 아니며 "doGrandpaStuff"라고 부를 수 있습니다.
class Grandpa
{
public function __construct()
{
echo"Hello Kiddo";
}
}
class Papa extends Grandpa
{
public function __construct()
{
}
public function CallGranddad()
{
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
}
public function needSomethingFromGrandDad
{
parent::CallGranddad();
}
}
PHP 7에서 u는 사용할 수 있습니다
parent::parent::__construct();
'Programming' 카테고리의 다른 글
Python3에서 '이진 문자열'을 일반 문자열로 변환하는 방법은 무엇입니까? (0) | 2020.05.12 |
---|---|
사용자가 매핑 한 섹션이 열린 파일에서 요청한 작업을 수행 할 수 없습니다. (0) | 2020.05.12 |
팬더 : 단일 열에 apply () 함수를 어떻게 사용할 수 있습니까? (0) | 2020.05.12 |
소스 트리-푸시되지 않은 커밋 실행 취소 (0) | 2020.05.12 |
F- 문자열로 소수점 이하의 고정 숫자 (0) | 2020.05.12 |