PHP 클래스
1.클래스정의
클래스란?
클래스는객체의변수와함수를정의하는템플릿이며,이에따라변수로표현되는데이터영역과이러한데이터영역에접근할수있는함수로구성됩니다.클래스내에정의된변수를멤버변수(member variable)라고하고함수를메쏘드(method)라고합니다. C++과같은객체지향언어에서는멤버변수를데이터멤버,메쏘드를멤버함수라고호칭합니다. PHP에서클래스를사용하는것은 C++또는자바와거의비슷합니다.
클래스정의
클래스를정의(class definition)할때는키워드"class"를사용합니다.클래스를구성하는멤버변수와메쏘드를정의할때는"var"과"function"이라는키워드를사용합니다."function"은일반함수를정의할때도사용되지만"var"은클래스의멤버변수를정의할때만사용되는키워드로,멤버변수를정의할때는반드시명시하여야합니다.예를들어클래스는아래와같이정의합니다.이예는 PHP 매뉴얼에있는것으로수정하지않고가져왔습니다.이예에서는 $items라는멤버변수와 add_item, remove_item라는메쏘드가정의되어있습니다.
classCart{
var $items; // Items in our shopping cart
// Add $num articles of $artnr to the cart
function add_item ($artnr, $num){
$this->items[$artnr]+= $num;
}
// Take $num articles of $artnr out of the cart
function remove_item ($artnr, $num){
if($this->items[$artnr]> $num){
$this->items[$artnr]-= $num;
returntrue;
}else{
returnfalse;
}
}
}
멤버변수의초기화
PHP에서는멤버변수값을아래와같이상수또는변수를이용하여초기화할수있습니다.
상수로초기화할때:
classCart{
var $items =0; // Items in our shopping cart
}
변수로초기화할때(1):
classCart{
var $items; // Items in our shopping cart
functionCart($items){
$this->items = $items;
}
}
변수로초기화할때(2):
$items =0;
classCart{
var $items = $GLOBALS["items"]; // Items in our shopping cart
}
반면 PHP4에서는var변수에는상수로만초기화할수있고,상수가아닌값을가지고초기화할때는생성자를이용하여야합니다.즉,var $items = $GLOBALS["items"];와같은표현은허용하지않습니다.
따라서아래와같은표현은 PHP4에서는허용하지않습니다.
classCart{
var $todays_date = date("Y-m-d");
var $name = $firstname;
var $owner ='Fred '.'Jones';
var $items = array("VCR","TV");
}
PHP4에서초기화할때동일한결과를얻으려면아래와같이생성자를이용합니다.
classCart{
var $todays_date;
var $name;
var $owner;
var $items;
functionCart(){
$this->todays_date = date("Y-m-d");
$this->name = $GLOBALS['firstname'];
/* etc. . . */
}
}
PHP4 예약어
stdClass
stdClass는Zend에서내부적으로사용하고있는예약어입니다.따라서사용자는클래스명으로 stdClass를사용할수없습니다. get_declared_classes()함수를사용하면현재스크립트에정의된클래스명을배열에담아되돌려줍니다.따라서이함수를이용하면 stdClass의존재를확인할수있습니다.
php
classVegetable{
}
classSpinachextendsVegetable{
}
$arr_class = get_declared_classes();
while(list($k,$v)=each($arr_class)){
echo("\$arr_class[$k]=$v
\n");
}
?>
이문서를실행하면아래와같은결과를얻을수있습니다.
$arr_class[0]=stdClass
$arr_class[1]=OverloadedTestClass
$arr_class[2]=Directory
$arr_class[3]=OCI-Lob
$arr_class[4]=vegetable
$arr_class[5]=spinach
위예제의실행결과를보면,사용자가정의한 vegetable, spinach 외에도 stdClass,OverloadedTestClass,Directory, OCI-Lob가있는것을볼수있습니다.좀더자세한것은메뉴"클래스&객체 함수 >> get_declared_classes()"를살펴보시기바랍니다.
매직함수(magic function)
__sleep, __wakeup과같이"__"로시작하는매직함수는 PHP 클래스내에서특수한목적으로사용됩니다.따라서이함수들이가지고있는문서화된매직기능을사용할필요가없다면클래스내에이함수들을정의해서는안됩니다.자세한것은메뉴에서"매직함수"장을살펴보기바랍니다.
$this가무엇에쓰는물건인고?
클래스메쏘드내에서만사용되며,클래스의현재인스턴스를참조할때사용하는변수이며,예를들어현재객체내에 something라고명명된임의의변수또는함수를참조하기위해서는 $this->something을사용하여야합니다.즉,"$this"의의미는new연산자에의해생성될객체자신을의미합니다.그러니아직생성되지않은객체자신을의미하는의사(擬似)변수(pseudo variable)이며,"my own"또는"current object"라고불리웁니다.
앞에서클래스를붕어빵틀과같다고했습니다.정의된클래스에의해생성된객체는붕어빵틀로만들어낸수많은붕어빵이지요.아래예에서본다면, $붕어빵1->make("특급밀가루")으로 make()메쏘드에접근한다면이때 make()메쏘드내의 $this는 $붕어빵1을의미하고, $붕어빵2->make("중급밀가루")으로접근한다면이때 $this는 $붕어빵2를의미하고, $붕어빵3->make("저급밀가루")으로접근한다면이때 $this는 $붕어빵3을의미합니다.
class붕어빵{
var재료;
function make($재료){
$this->재료= $재료;
......
}
}
$붕어빵1=new붕어빵;// 인스턴스 "붕어빵1"
$붕어빵2=new붕어빵;// 인스턴스 "붕어빵2"
$붕어빵3=new붕어빵;// 인스턴스 "붕어빵3"
$붕어빵1->make("특급밀가루");
$붕어빵2->make("중급밀가루");
$붕어빵3->make("저급밀가루");
2.객체생성
객체생성=객체초기화(object initialization)=인스턴스화(instantiation)
클래스는붕어빵을만드는틀(= type,=template)과같은것으로,클래스내에정의된메쏘드와멤버변수를사용하기위해서는틀을가지고붕어빵을만드는것같이객체를생성하여야합니다.객체(object)를초기화하는방법은new연산자를사용하여객체를변수에인스턴스시키는것입니다.
classCart{
var $items; // Items in our shopping cart
// Add $num articles of $artnr to the cart
function add_item ($artnr, $num){
$this->items[$artnr]+= $num;
}
// Take $num articles of $artnr out of the cart
function remove_item ($artnr, $num){
if($this->items[$artnr]> $num){
$this->items[$artnr]-= $num;
returntrue;
}else{
returnfalse;
}
}
}
$cart =newCart;
$cart->add_item("10",1);
위와같이하면클래스Cart에대한객체 $cart가생성됩니다.객체함수 add_item()은장바구니에품목번호"10"의수량을1개추가하기위해호출됩니다.
지정연산자"->"의의미
"->"는객체의멤버변수또는메쏘드를지정하는데사용되는지정연산자입니다. C++언어를접해본분은쉽게이해하시겠지만,new연산자로생성되는객체를나타내는객체명에는실제로객체의멤버(변수또는함수)가존재하는것이아니라객체의멤버가존재하는메모리상에위치를나타내는주소(adress)가담겨져있습니다.이와같이객체지향언어에서는주소를가지고멤버를참조하려면아래와같이지정연산자"->"를이용하게됩니다.
멤버변수를참조할때:객체명->변수;
메쏘드를참조할때 :객체명->함수;
C++언어에서는"->"를화살표멤버연산자라고말하며,"->"의앞쪽에있는식별자(여기서는객체명)가포인터(pointer;주소를의미함)일때그멤버를참조하기위한연산자입니다.
지역변수에초기화된객체
객체를지역변수에인스턴스할수있기때문에,클래스를정의하고객체를생성하는것을하나의모듈로개발할수있습니다.
예제코드:
php
function class_in_function(){
class test {
var $a =10;
function test(){
echo "함수 내에 정의된 클래스의 생성자 실행
";
}
function echo_test(){
echo "함수 내에 정의된 클래스의 멤버변수 \$a의 값 = ".$this->a."
";
}
}
$obj =new test;
$obj->echo_test();
}
class_in_function();
?>
실행결과:
함수내에정의된클래스의생성자실행
함수내에정의된클래스의멤버변수 $a의값=10
객체생성할때생성자명을가변함수로지정하기
$classname ="MiniDB";
$obj =new $classname();
이코드는 PHP와 PHP4 모두에서정상적으로동작합니다.
메쏘드명을변경하기(가변함수)
PHP의매뉴얼을보면가변함수(variable function)를지원하는데이것은변수명뒤에괄호가왔을때, PHP는그이름을가진함수를찾아실행하는것입니다.이것은클래스의메쏘드에서도그대로사용할수있습니다.
class test {
function A(){
echo "나 A 함수
\n";
}
}
$obj =new test;
$method ="A";
$obj->$method();
이것을응용하여같은실행문으로 A0, A1, A2라는메쏘드에번갈아가면서접근하려면역시가변함수를사용하면됩니다.
class test {
function A0(){
echo "나 A0 함수
\n";
}
function A1(){
echo "나 A1 함수
\n";
}
function A2(){
echo "나 A2 함수
\n";
}
}
$obj =new test;
for($i=0;$i<3;$i++){
$method ="A$i";
$obj->$method();
}
위에것은모두 PHP3와 PHP4에서모두동작되는코드입니다.만약, PHP4에서만동작시켜도무방하다면아래와같이중괄호를이용하면소스를간결하게코딩할수있습니다.
for($i=0;$i<3;$i++){
$obj->{"a$i"}();
}
객체명을변경하기(가변변수)
가변변수(VariableVariables)의유용함은모두알고있겠지만 PHP4에서는별문제가없지만 PHP에서객체변수를가변변수로사용하기는그리쉽지않습니다.
class test {
var $hello ="hello world";
}
$obj =new test;
$a ="obj";
echo $$a->hello;// or echo ${$a}->hello;
PHP에서위와같이작성하여실행한다면,
Object
Parse error: parse error,...... test.php3 on line 9
와같은에러를만나게됩니다.그러나 PHP4에서는객체변수에도가변변수를제대로지원하기시작했습니다.따라서위의예제가에러없이잘실행되지요.그러면 PHP에서는객체변수의이름을변경할수없을까요?아래와같이 $GLOBALS 배열을사용해보세요.아무문제없이잘실행될겁니다.
class test {
var $hello ="hello world";
}
$obj =new test;
$a ="obj";
echo $GLOBALS[$a]->world();
따라서 PHP3와 PHP4 모두에서동작되기를바란다면 $GLOBALS 배열을이용하여작성하세요.
배열구조의멤버변수를가변변수로다루는방법
class test {
var $arr = array();
function test(){
$this->arr[0]=0;
$this->arr[1]=1;
}
}
$obj =new test;
위와같이클래스 test에배열구조의멤버변수가있을때,이러한멤버변수의배열요소에접근하려면 $obj->arr[0];와같이사용하면됩니다.여기서멤버변수명"arr"을가변변수로처리하려면,
$prop ="arr";
$obj->{"$prop"}[0];
와같이가변변수 $prop를중괄호로묶어주세요.여기서겹따옴표는생략해도됩니다. PHP3와 PHP4에서모두잘동작할것입니다.
3.클래스상속
클래스를상속하려면?
기존에이미작성된클래스를상속(class inheritance)받으면이미작성된메쏘드와멤버변수를그대로이어받게됩니다.상속받은특성에덧붙여새로운특성을추가하는방법으로새로운클래스를정의하게됩니다.이와같이기존의클래스로부터특성을이어받는것을상속이라고합니다.이때확장된클래스를정의하기위해"extends"라는키워드를사용합니다.
부모클래스&자식클래스에관련된용어
기존의클래스와확장된클래스를나타내는용어는객체지향언어마다다양하게사용되고있습니다.그러나어떤용어를사용하더라도같은의미로사용되고있다고이해하시면됩니다.
기존의클래스확장된클래스
용어영문용어영문
기반클래스baseclass파생클래스 derived class
수퍼클래스superclass서브클래스subclass
부모클래스 parent class자식클래스 child class
클래스상속예제
classCart{
var $items; // Items in our shopping cart
// Add $num articles of $artnr to the cart
function add_item ($artnr, $num){
$this->items[$artnr]+= $num;
}
// Take $num articles of $artnr out of the cart
function remove_item ($artnr, $num){
if($this->items[$artnr]> $num){
$this->items[$artnr]-= $num;
returntrue;
}else{
returnfalse;
}
}
}
class Named_Cart extendsCart{
var $owner;
function set_owner ($name){
$this->owner = $name;
}
}
클래스 Named_Cart는클래스Cart의모든변수와함수를그대로상속받게되며,새로운멤버인변수 $owner과함수 set_owner()를추가하여정의합니다.앞서배운new연산자를이용하여클래스 Named_Cart의객체를생성한후장바구니주인을지정하거나주인이누구인지확인할수있습니다.아울러부모클래스Cart에있는장바구니관련함수를그대로사용할수있습니다.
$ncart =new Named_Cart; // Create a named cart
$ncart->set_owner ("kris");// Name that cart
print $ncart->owner; // print the cart owners name
$ncart->add_item ("10",1);// (inherited functionality from cart)
단일상속
PHP는다중상속(multiple inheritance)를지원하지않으며,오로지단일상속만지원합니다.
4.생성자
생성자란?
생성자(constructor)는클래스의새로운인스턴스가생성될때자동적으로호출되는클래스내의함수이며,클래스명과동일한이름를갖는특수한메쏘드입니다.
classCart{
var $items; // Items in our shopping cart
// Add $num articles of $artnr to the cart
function add_item ($artnr, $num){
$this->items[$artnr]+= $num;
}
// Take $num articles of $artnr out of the cart
function remove_item ($artnr, $num){
if($this->items[$artnr]> $num){
$this->items[$artnr]-= $num;
returntrue;
}else{
returnfalse;
}
}
}
class Auto_Cart extendsCart{
function Auto_Cart (){
$this->add_item ("10",1);
}
}
위의예제는클래스 Auto_Cart가new연산자로만들어질때마다품목번호"10"의수량이1을갖도록장바구니를초기화시키는생성자를새로이포함하여정의하였습니다.
생성자에전달되는인자
생성자는필요하면선택적으로인자(argument)를전달할수도있기때문에매우유용하게사용됩니다.
class Constructor_Cart extendsCart{
function Constructor_Cart ($item ="10", $num =1){
$this->add_item ($item, $num);
}
}
// Shop the same old boring stuff.
$default_cart =new Constructor_Cart;
// Shop for real...
$different_cart =new Constructor_Cart ("20",17);
PHP3와 PHP4 생성자사이에발생하는미묘한차이
PHP에서는클래스와동일한이름을가진함수를생성자로처리하고있습니다.따라서아래와같은경우에클래스 B의이름과동일한이름의함수 B()가없으므로객체를생성할때실행할생성자가없습니다.
class A {
function A(){
echo "I am the constructor of A.
\n";
}
}
class B extends A {
function C(){
echo "I am a regular function.
\n";
}
}
// no constructor is being called in PHP.
$b =new B;
그러나만약아래와같이클래스 A에함수 B()가정의되어있다면설사클래스 B를가지고객체를생성하더라도클래스 A에있는일반함수 B()를클래스 B의생성자로인식합니다.즉, PHP에서는함수 B()가클래스 B에속해있는지아니면부모클래스로부터상속된함수인지를인식하지못합니다.따라서객체 $b를생성할때클래스 A에있는일반함수 B()를생성자로써실행하게되는것이지요.
class A {
function A(){
echo "I am the constructor of A.
\n";
}
function B(){
echo "I am a regular function named B in class A.
\n";
echo "I am not a constructor in A.
\n";
}
}
class B extends A {
function C(){
echo "I am a regular function.
\n";
}
}
// no constructor is being called in PHP.
$b =new B;
클래스 B에속하지도않은,부모클래스로부터상속된일반함수 B()를클래스 B의생성자로인식한다는것은대부분우리가전혀의도하지않는일로잘못하다가는원치않는결과를초래할수도있습니다.객체지향언어에서말하는생성자의구분이모호해진다는것이지요.이러한문제를 PHP4에서는바로잡았습니다.단지이름만같다고생성자로처리하는것이아니라반드시해당클래스내에포함되어있는것만생성자로처리하도록수정하였습니다.따라서위의예를 PHP4에서수행한다면클래스 A에속한일반함수 B()를생성자로써실행하지는않습니다.
대신에 PHP4에서는생성자와관련하여새로운기능이추가되었습니다.파생클래스에서생성자가정의되어있지않으면그부모클래스에정의된생성자가실행하도록수정되었습니다.즉,위의예에서보면객체 $b를생성할때클래스 B에해당하는생성자 B()함수가정의되어있지않으므로그부모클래스의생성자인 A()가생성자로수행됩니다.
이러한 PHP3와 PHP4 사이의미묘한차이를명확히구분하지못한상태에서생성자를다루게되면프로그램이매우심각한오류에빠질수있다는것을참고하시기바랍니다.
*****주의*****
PHP4에서의개선내용은http://www.php.net/manual/en/language. ··· ctor.php에서 문서화된 내용입니다만 실제로 PHP4는 이 문서와 같이 동작하지 않는 것으로 보고되고 있습니다(아래 주소 참조할 것).
http://www.phpbuilder.com/lists/php-do ··· 0100.php
이러한문제로인하여2003년2월17일 bugs.php.net에공식적으로버그리포팅되어있습니다.
http://bugs.php.net/bug.php?id=22253
2003년2월17일당시에는 PHP 버전4.3.1이공개된시점으로이이후버전에서도이버그는개선되지않고있습니다.위에서언급한www.phpbuilder.com에의하면 PHP3와 php4가동일하게동작하며,단지 PHP5에서만개선된내용대로동작하고있음을알수있습니다.
5.범위연산자
범위연산자란?
PHP4에서만지원되며클래스와메쏘드또는클래스와멤버변수를연결시켜주는일로범위연산자(scope resolver)뒤에나오는메쏘드와멤버변수의스코프(사용범위)를지정하는일을하는것입니다.
클래스명::메쏘드명
클래스명::멤버변수명
범위연산자사용목적
1.인스턴스되지않은클래스의메쏘드에접근할때
2.부모클래스의메쏘드와멤버변수에접근할때
인스턴스되지않은클래스에있는메쏘드에접근할때
class A {
function example(){
echo "클래스 A에 정의된 메쏘드 example.
\n";
}
}
A::example();
아직클래스 A에대한객체가생성되기전이지만범위연산자를이용하면일반함수처럼실행시킬수있습니다.그러나클래스 A에대한객체가전혀생성되어있지않으므로클래스외부에서이함수에접근할때는이함수내에 $this 객체를사용해서는안됩니다.물론일반함수와마찬가지로지역변수및전역변수를사용할수는있습니다.
class A {
var $var ="초기값";
function example(){
echo "클래스 A에 속한 메쏘드 example.
\n";
echo $this->var."
\n";
}
}
A::example();
위의예제를보면아직클래스 A에대한객체가생성되지않았으므로멤버변수 $var에대한기억장소가할당되지도않았고더구나초기값을설정할수도없습니다.그러니아무리범위연산자를이용하여메쏘드 example()에접근한다해도멤버변수 $var의초기값을나타낼수는없을것입니다.실험해본바로는이경우 $this->var의값이 NULL로처리되는것같습니다.
부모클래스의메쏘드에접근할때
class A {
function example(){
echo "클래스 A에 정의된 메쏘드 example.
\n";
}
}
class B extends A {
function example(){
echo "클래스 B에서 재정의된 메쏘드 example.
\n";
A::example();
}
}
$b =new B;
$b->example();
이예의출력결과를보면아래와같이나타날것입니다.
클래스 B에서재정의된메쏘드 example.
클래스 A에정의된메쏘드 example.
범위연산자는클래스가상속되었을때재정의되기전의부모클래스에있는메쏘드에접근할때유용하게사용될수있습니다.
부모클래스의멤버변수에접근할때
php.net의문서설명과는달리아직공개되지않는어떤방법이있는지는모르겠으나부모클래스의멤버변수로접근하는방법에대하여는문서화되지않은것같습니다.
6.부모키워드
부모클래스의메쏘드호출
보통부모클래스에서선언된메쏘드를자식클래스에서재정의하는이유는크게두가지가있습니다.
1.부모클래스메쏘드를완전히새롭게정의하기위하여
2.부모클래스메쏘드의기능에새로운기능을추가하기위하여
첫번째기능은부모클래스의메쏘드를무시하고메쏘드에새로운정의를함으로써부모클래스의메쏘드정의를숨기는것입니다.그러나때로는부모클래스의메쏘드를모두지우는것보다는추가적인기능이필요한경우가있습니다.이같은경우에는부모클래스의메쏘드와자식클래스에서재정의된메쏘드를모두수행하게될것입니다.즉,재정의된메쏘드구문내에서부모클래스의메쏘드를호출할수있어야하며필요한기능만추가적으로작성하면될것입니다.이럴때부모클래스의메쏘드를호출하기위해서사용하는키워드가 parent입니다.자바에서의키워드super와같은역할을하며이것은그메쏘드호출을상위클래스로전달합니다.
부모키워드 parent는 $this 키워드와비슷하게이클래스의부모클래스를나타내는위치지정자입니다.현재클래스의부모클래스를참조해야되는경우에는부모키워드 parent를사용할수있습니다.
class A {
function example(){
echo "클래스 A에 정의된 메쏘드 example.
\n";
}
}
class B extends A {
function example(){
echo "클래스 B에서 재정의된 메쏘드 example.
\n";
parent::example();
}
}
$b =new B;
$b->example();
이예의출력결과를보면아래와같이나타날것입니다.
클래스 B에서재정의된메쏘드 example.
클래스 A에정의된메쏘드 example.
앞장범위연산자에서설명한대로키워드 parent 대신에extends다음에기술된부모클래스명을직접사용해도됩니다.
parent::example(); ------> A::example();
키워드 parent를써야될이유
위의예에서부모클래스를 A가아닌 A1으로부터상속받도록수정하여야한다면아래와같이extends다음에있는부모클래스명을변경하는것으로모든작업은끝나게됩니다.만약 parent::example()가아닌 A::example()라고작성하였었다면이부분도 A1::example()라고수정하여야할것입니다.결국수정할때손이더많이가야하는것이지요.그러니부모클래스에있는메쏘드에접근하는경우라면키워드 parent를이용하는것이소스코드를관리하는데훨씬유리할것입니다.
class B extends A1 {
function example(){
echo "클래스 B에서 재정의된 메쏘드 example.
\n";
parent::example();
}
}
$b =new B;
$b->example();
7매직함수
__sleep, __wakeup과같이"__"로시작하는매직함수(magic function)는 PHP 클래스내에서특수한목적으로사용됩니다.따라서이함수들이가지고있는문서화된매직기능을사용할필요가없다면클래스내에이함수들을정의해서는안됩니다.
__sleep
serialize 함수를통해객체를직렬화할때해당클래스에매직함수 __sleep가정의되어있는지확인합니다.만약정의되어있다면객체를직렬화하기전에 __sleep 함수를수행합니다.이함수는직렬화하기전에객체멤버에대하여조작해야하는작업,또는직렬화하기전에미리수행해야하는작업(예를들어데이터베이스연결종료등)을수행할수있습니다. __sleep 함수는직렬화할객체의모든멤버변수의이름을변수에담아반환합니다.
classScott{
var $error;
var $svar = array();
functionScott(){
$this->svar['Hello']="World";
}
function __sleep(){
$this->svar['Hello']="Yawn";
// return list of instance-variables to be serialized
return array('error','svar');
}
}
$x =newScott();
print_r($x);
$y = serialize($x);
$z = unserialize($y);
print_r($z);
__wakeup
unserialize 함수를통해문자열을객체화할때해당클래스에매직함수 __wakeup가정의되어있는지확인합니다.만약정의되어있다면객체화하기전에 __wakeup 함수를수행합니다.이함수를수행할때객체화하기전에객체를상대로수행해야하는작업,또는객체화하기전에미리수행해야하는작업(예를들어데이터베이스연결등)을수행할수있습니다.
classScott{
var $error;
var $svar = array();
functionScott(){
$this->svar['Hello']="World";
}
function __sleep(){
$this->svar['Hello']="Yawn";
// return list of instance-variables to be serialized
return array('error','svar');
}
function __wakeup(){
$this->svar['test']="I'm here!";
}
}
$x =newScott();
print_r($x);
$y = serialize($x);
$z = unserialize($y);
print_r($z);
'개발 > php' 카테고리의 다른 글
변수값을 함수이름으로 사용하여 함수 실행 (0) | 2013.08.20 |
---|---|
한글자르기 (0) | 2013.08.20 |
Using MySQL Stored Procedures with PHP mysql/mysqli/pdo (0) | 2013.08.18 |
configure 옵션들 (0) | 2013.08.15 |
PHP 5.5.x (0) | 2013.08.15 |