50. PHP 클래스 사용하기
클래스 선언은 class 키워드로 합니다. 이후 바로 클래스 이름이 나옵니다. 클래스 이름은 PSR(PHP 표준 권고 - PHP Standard Recommendation)-01에 따라 대문자로 시작하고 단어 간의 연결마다 대무자를 사용하는 StudlyCaps 형식을 따릅니다. Pascal Case라고 부르기도 합니다.
class Fruit
클래스는 특정 역할을 하는 타입을 말합니다. 내부적으로 멤버 변수와 메서드를 가질 수 있습니다. 클래스 타입의 변수를 인스턴스라고 부릅니다.
(멤버 변수 : 클래스 안에서 선언된 변수 / 메서드 : 클래스 안에서 선언된 함수)
$fruit = new Fruit();
$drink는 인스턴스, Drink는 타입을 정의하는 클래스입니다.
(인스턴스는 붕어빵 타입은 붕어빵 틀이라고 생각하시면 됩니다)
멤버 변수는 클래스의 인스턴스 가지고는 속성입니다. 클래스 안에서 선언된 변수를 멤버 변수라고 부릅니다.
프로퍼티(property)라고 부르기도 합니다.
// 멤버변수
private $name;
private $color;
클래스 안에 정의된 함수를 메서드(method)라고 부릅니다.
public function tell(){}
메서드는 함수와 동일하게 리턴 값을 가질 수 있습니다.
// method
public function tell()
{
echo "이 과일은 {$this->name} 입니다. ";
echo "색상은 {$this->color} 입니다. <br />";
}
생성자는 인스턴스가 처음 생성될 때 자동으로 실행되는 초기화 메서드입니다. __construct라는 이름입니다.
// constructor
public function __construct()
{
$this->name = "사과";
$this->color = "빨강색";
}
다른 언어에서 생성자는 클래스 이름과 동일한 것과는 차이가 있으니 주의 바랍니다. 다만 클래스 개념이 처음 도입된 PHP4 버전의 생성자는 __construct() 대신 클래스 이름이 사용되었습니다.
소멸자는 인스턴스가 소멸할 때 자동으로 실행되는 메서드입니다. __destruct라는 이름입니다.
function __destruct()
{
echo "인스턴스가 소멸되었습니다.";
}
$this는 인스턴스 자신을 나타내는 키워드입니다. 인스턴스에 속한 메서드나 멤버 변수를 호출할 때 $this로 참조합니다.
// 멤버 변수
public $name;
...
// construct
public function __construct()
{
$this->name = "사과";
...
}
위 예시에서 멤버 변수 $name을 참조하기 위해 $this를 사용했습니다.
멤버 변수에서 주의해야 할 점은 PHP의 변수에는 $ 기호를 붙이지만 멤버 변수에 접근할 때는 $ 기호를 붙이지 않습니다.
$this->name = "사과";
하지만 멤버 변수를 정의할 때는 $ 기호를 붙여야 합니다.
private $name;
인스턴스의 멤버 변수나 메서드를 참조할 때는 -> 키워드를 씁니다. 배열에서 키, 값을 가지고 올 때 사용하는 =>와 비슷하지만 다른 기능을 합니다. 다른 언어에서 . 으로 가지고 오는 것과 헷갈리지 않도록 합니다.
아래 코드는 클래스 내부에서 멤버 변수를 참조하는 예시입니다.
$this->name = "사과";
아래 코드는 클래스 외부에서 메서드를 참조하는 예시입니다.
$fruit->tell();
return $this는 인스턴스 자신을 리턴한다는 뜻입니다. 주로 하나의 객체에 여러 가지 메서드를 연쇄적으로 호출하는 메서드 체이닝을 사용할 때 사용합니다.
public function change_fruit($name)
{
$this->name = $name;
return $this;
}
아래처럼 사용한다.
change_color('초록색')->tell();
"" 문자열이나 히어닥 문법은 내부에서 변수를 치환할 수 있습니다. 이때 만약 복합형 변수일 경우 ${변수} 형식을 이용해서 복합형 변수의 값을 가져올 수 있습니다. 이 규칙은 클래스와 무관하게 PHP 전체에서 동일합니다.
public function tell()
{
echo "이 과일은 {$this->name} 입니다. ";
echo "색상은 {$this->color} 입니다. <br />";
}
멤버 변수나 메서드 이름 앞에 static을 붙이면 정적인 속성을 갖습니다. 정적인 변수나 메서드를 인스턴스에 속하지 않고 클래스에 속합니다.
//static method
public static function factory()
{
return new Fruit();
}
정적인 메서드나 프로퍼티를 호출할 때는 ->를 사용하지 않고 :: 를사용합니다.
Fruit::factory()
정적인 메서드나 프로퍼티를 내부에서 참조하는 것은 self를 이용합니다. 즉 클래스의 데이터를 이용할 때는 self를, 인스턴스의 데이터를 이용할 때는 $this를 사용합니다.
public static function factory2()
{
return self::factory();
}
static이라는 키워드가 메서드가 아닌 일반 함수 안에서 사용되면 함수 자체가 실행이 끝났음에도 상태를 가지고 있는 코루틴으로 작동합니다. 같은 키워드지만 사용되는 곳에 따라 의미가 다릅니다.
function func_static()
{
static $cnt = 1;
echo $cnt;
$cnt++;
}
func_static();
func_static();
결과는 아래와 같습니다.
1
2
예제에서 정적 메서드 factory는 팩토리 디자인 패턴으로 인스턴스를 생성합니다.
// static method
public static function factory()
{
return new Fruit();
}
php는 new Drink->order()처럼 생성자 호출 후 곧바로 다른 인스턴스의 메서드를 호출하는 생성자 메서드 체이닝이 불가능합니다. 꼭 하고 싶다면 (new Drink())->order() 형식으로 생성자를 ()로 감싸줘야 합니다. 이러한 불편한 때문에 정적 팩토리 메서드를 만드는 경우가 많습니다.
추가적으로 팩토리 패턴은 생성자를 여러분 호출해도 인스턴스를 하나만 만드는 싱글톤 패턴과 결합되어 사용되는 경우도 있습니다. 아래는 팩토리 + 싱글톤 패턴의 예시입니다.
private static $fruit = null;
public static function factory()
{
if (self::$fruit == null){
self::$fruit = new fruit();
}
return self::$fruit;
}
정적 메서드 factory()를 통해 인스턴스를 생성할 경우, 이미 생성된 Sample 객체가 있으면 생성된 객체를 반환합니다. 객체가 없다면 객체를 생성 후 반환합니다.
전체 코드
<?php
class Fruit
{
// member variable
public $name;
public $color;
// constructor
public function __construct()
{
$this->name = "사과";
$this->color = "빨강색";
}
// destruct
public function __destruct()
{
echo "인스턴스가 소멸되었습니다.";
}
// method
public function tell()
{
echo "이 과일은 {$this->name} 입니다. ";
echo "색상은 {$this->color} 입니다. <br />";
}
// method. return $this
public function change_color($color)
{
$this->color = $color;
return $this;
}
public function change_fruit($name)
{
$this->name = $name;
return $this;
}
// static method
public static function factory()
{
return new Fruit();
}
public static function factory2()
{
return self::factory();
}
}
$fruit = new Fruit();
$fruit->change_color("초록색");
$fruit->tell();
echo "<br />";
Fruit::factory()->change_fruit("포도")->change_color('초록색')->tell();
?>