단일화된 생성자(Unified Constructors)
생성자명
생성자(constructor)는 'new' 키워드에 의하여 클래스의 새로운 인스턴스가 생성될 때 자동적으로 호출되는 클래스 내의 특별한 메소드이며, 객체의 다른 멤버가 사용되기 전에 필요로 하는 초기화같은 작업을 생성자를 통하여 수행하게 됩니다.
PHP3 및 Zend 엔진 1.0에서의 생성자는 클래스명과 동일한 이름을 가지게 됩니다. 아래와 같이 클래스명과 동일한 이름의 메소드가 존재한다면 이것을 자동적으로 생성자로 취급합니다.
[code php;gutter:false]
<?php
class Shape {
function Shape() {
// shape initialization code
…
}
…
};
?>
[/code]
Zend 엔진 2.0에서의 생성자는 클래스명과 관계없이 단순히 __construct()라는 이름으로 단일화된 생성자를 호출할 수 있습니다.
[code php;gutter:false]
<?php
class Shape {
function __construct() {
// shape initialization code
…
}
…
};
?>
[/code]
생성자명을 __construct()로 단일화한 이유
PHP3 및 Zend 엔진 1.0에서 생성자명으로 생기는 문제
클래스의 상속관계에 변화가 생겨서 수정하는 경우를 생각해 보세요. 파생한 클래스로부터 부모클래스의 생성자를 호출하는 것은 흔히 있는 일이기 때문에 Zend 엔진 1.0에서 수행하던 방법에 의하여 작성된 상속관계에 변화가 생겨 클래스를 이동하려면 약간의 수고가 필요할 것입니다.
수정하기 전에 작성된 초기의 클래스 상속관계가 아래와 같다고 예를 들어보지요.
[code php;gutter:false]
<?php
class Shape {
function Shape() {
// shape initialization code
…
}
…
};
class Square extends Shape {
function Square() {
parent::Shape();
// square-specific initialization code
…
}
…
};
?>
[/code]
어떠한 이유에 의하여 클래스 Square와 Shape 사이에 새로운 클래스 Rectangle가 삽입되어 상속관계에 변화가 생겼다고 가정해 보지요.
[code php;gutter:false]
<?php
class Shape {
function Shape() {
// shape initialization code
…
}
…
};
class Rectangle extends Shape {
function Rectangle() {
parent::Shape();
// rectangle initialization code
}
…
};
class Square extends Rectangle {
function Square() {
parent::Rectangle();
// square-specific initialization code
…
}
…
};
?>
[/code]
수정전과 후의 코드를 비교해 보았을 때 클래스 Square의 생성자 내에서 부모클래스를 호출하는 부분에 변화가 생긴 것을 볼 수 있습니다. 원래는 클래스 Square의 부모클래스가 Shape였으나 클래스 Square와 Shape 사이에 새로운 클래스 Rectangle가 삽입되었기 때문에 클래스 Square의 부모클래스가 Rectangle로 바뀌었습니다. 이에 따라 부모클래스를 호출하는 부분이 parent::Shape()에서 parent::Rectangle()로 수정되었습니다.
상속관계에 변화가 생길 때마다 생성자 내용을 일일이 수정해야 한다는 것은 여간 신경쓰이는 일이 아닙니다. 문서의 규모가 커지고 상속관계가 복잡해 진다면 다소 부담스러울 수도 있겠지요.
이러한 이유로 Zend 엔진 2.0에서의 생성자는 클래스명과 관계없이 단순히 __construct()라는 이름으로 생성자를 호출할 수 있도록 개선되었습니다.
Zend 엔진 2.0에서 단일화된 생성자
위의 예를 Zend 엔진 2.0에서는 어떻게 처리되는지 살펴보겠습니다. Zend 엔진 2.0으로 작성된 수정하기 전의 초기의 클래스 상속관계는 아래와 같을 것입니다.
[code php;gutter:false]
<?php
class Shape {
function __construct() {
// shape initialization code
…
}
…
};
class Square extends Shape {
function __construct() {
parent::__construct();
// square-specific initialization code
…
}
…
};
?>
[/code]
클래스 Square와 Shape 사이에 새로운 클래스 Rectangle가 삽입되어 상속관계에 변화가 생겼을 때의 수정된 소스는 아래와 같겠지요.
[code php;gutter:false]
<?php
class Shape {
function __construct() {
// shape initialization code
…
}
…
};
class Rectangle extends Shape {
function __construct() {
parent::__construct();
// rectangle initialization code
}
…
};
class Square extends Rectangle {
function __construct() {
parent::__construct();
// square-specific initialization code
…
}
…
};
?>
[/code]
Zend 엔진 1.0으로 작성된 소스와는 달리 수정전과 후의 코드를 비교해 보았을 때 클래스 Square의 생성자 내에서 부모클래스를 호출하는 부분에 변화가 전혀 없음을 볼 수 있습니다.
Zend 엔진 2.0에서는 생성자명을 클래스명 대신에 '__construct()'라는 이름으로 호출할 수 있도록 생성자 선언 방법을 표준화함으로써 클래스의 상속관계에 변화가 생겼을 때에 생성자에서 부모클래스를 호출하는 부분을 일일이 수정해야 할 필요가 없어졌습니다. 이것이 생성자를 __construct()로 단일화했을 때에 얻을 수 있는 큰 이점이라 할 수 있지요.
Zend 엔진 2.0에서의 생성자 호출에 관한 하위호환성
생성자 호출 메카니즘
만약 Zend 엔진 2.0이 정의된 클래스에 __construct()를 발견할 수 없으면 하위 호환성을 가지기 위하여, Zend 엔진 1.0에서의 생성자, 즉 클래스명과 동일한 이름의 메소드를 찾을 것입니다.
따라서 아래와 같이 Zend 엔진 1.0용으로 작성된 소스를 Zend 엔진 2.0에서 수행하더라도 정상적으로 동작할 것입니다.
[code php;gutter:false]
<?php
class Shape {
function Shape() {
// shape initialization code for Zend Engine 1.0
…
}
…
};
?>
[/code]
같은 이유로 아래와 같이 Zend 엔진 1.0용 생성자와 Zend 엔진 2.0용 생성자가 모두 정의되어 있다면 Zend 엔진 1.0용 생성자는 무시되고 Zend 엔진 2.0용 생성자 __construct() 만 호출되겠지요.
[code php;gutter:false]
<?php
class Shape {
function Shape() {
// shape initialization code for Zend Engine 1.0
…
}
function __construct() {
// shape initialization code for Zend Engine 2.0
…
}
…
};
?>
[/code]
Zend 엔진 1.0 및 Zend 엔진 2.0 에서 모두 동작하는 생성자
Zend 엔진 1.0이 탑재된 PHP4에서 Zend 엔진 2.0과의 호환성을 가지도록 생성자를 정의한다면 아래와 같이 작성하면 가능하니라 생각합니다.
[code php;gutter:false]
<?php
class Shape {
function Shape() {
// shape initialization code for Zend Engine 1.0
$this->__construct();
}
function __construct() {
// shape initialization code for Zend Engine 2.0
…
}
…
};
$obj = new Shape();
?>
[/code]
위의 소스는 Zend 엔진 1.0과 2.0에서 모두 동일한 결과를 얻게 될 것입니다. Zend 엔진 1.0을 더 이상 필요없다면 Zend 엔진 1.0용 생성자인 Shape()을 완전히 삭제하면 되겠지요.
Zend 엔진 1.0용 생성자 Shape()에서 $this 객체를 이용하여 Zend 엔진 2.0용 생성자를 호출하기 때문에 static 멤버로는 접근할 수 없으며 반드시 인스턴스화한 객체를 가지고 접근할 때만 정상적으로 동작됩니다. 물론 생성자라는 것이 인스턴스화할 때만 동작하는 특별한 메소드이기 때문에 별 문제는 되지 않지만 좀더 소스 코드를 명료하게 작성한다면 이를 아래와 같이 $this 객체 대신에 클래스명과 범위연산자를 이용하면 될 것입니다. 수정된 코드에서의 단점이라면 현재 클래스명 Shape가 변경된다면 Shape::__construct() 부분도 함께 수정되어야 한다는 것이지요.
[code php;gutter:false]
<?php
class Shape {
function Shape() {
// shape initialization code for Zend Engine 1.0
Shape::__construct();
}
function __construct() {
// shape initialization code for Zend Engine 2.0
…
}
…
};
$obj = new Shape();
?>
[/code]