코드의 재사용은 OOP에 있어 중요한 부분중 하나 입니다. PHP에서는 상속(inheritance) 을 통해 이를 해결할 수 있습니다. 그러나 PHP의 상속 모델은 단일 상속으로 자식클래스는 하나의 부모 클래스만 상속 받을 수 있습니다. 그러므로 여러 클래스에서 상속 받는 것과 비슷한 효과를 내기 위해서는 클래스가 아닌 인터페이스로 선언하여 이를 구현하고 부모 클래스를 상속 받아야 합니다. 이 경우 같은 레벨의 클래스 마다 인터페이스를 구현해야 하는 중복된 코드가 발생하게 됩니다. 또한 상속은 결합도가 높아 상속의 남용은 코드를 유지 보수 하는데 있어 매우 힘든 상황이 생길 수 있습니다. 이를 해결하기 위해 PHP5.4에 등장한 것이 trait
입니다.
trait
은 클래스와 유사해 보이지만 함수들을 세분화되고(fine-grained) 그룹화하기 위한 것이 목적이며, 클래스와 다르게 인스턴스라는 개념이 없습니다.
Fine-Grained
하나의 작업을 작은 단위의 프로세스로 나눈 뒤, 다수의 호출을 통해 작업 결과를 생성해내는 방식
Coarse-Grained
하나의 작업을 큰 프로세스로 나눈 뒤, Single Call을 통해 작업 결과를 생성해내는 방식
trait
은 함수와 추상함수(abstract method)를 가질 수 있으며 여러 클래스에서 사용가능 합니다. 또한 접근지정자(public, private, protected)를 모두 사용할 수 있습니다.
PHP Traits
Trait은 trait
키워드를 사용하여 선언할 수 있습니다.
1
2
3
4
5
6
7
8
9
<?php
trait Message
{
public function msg($msg)
{
echo "message: $msg";
}
}
trait을 클래스에서 사용하기 위해서는 use
키워드를 사용해야 합니다. 함수를 호출하는 방식은 인스턴스 함수 호출과 비슷합니다.
use
키워드는 두가지로 사용됩니다. 클래스에서의 trait사용, namespace의 alias지정에서 사용됩니다.
1
2
3
4
5
6
7
8
9
10
11
<?php
class Welcome
{
use Message;
public function __construct()
{
$this->msg("Hello world!!");
}
}
Multiple Traits
클래스는 여러개의 trait을 사용할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?php
trait Hello
{
public function hello()
{
echo "Hello ";
}
}
trait World
{
public function world()
{
echo "world!!";
}
}
class Welcome
{
use Hello, World;
}
$welcome = new Welcome();
$welcome->hello();
$welcome->world();
// Hello world!!
Composing Multiple Traits
trait
은 use
키워드를 사용해서 합칠 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php
trait Hello
{
public function hello()
{
echo "Hello ";
}
}
trait World
{
public function world()
{
echo "world!!";
}
}
trait Message
{
use Hello, World;
public function message()
{
$this->hello();
$this->world();
}
}
class Welcome
{
use Message;
}
$welcome = new Welcome();
$welcome->message();
// Hello world!!
Hello
와 World
trait을 선언한 후 use
키워드를 사용하여 Message
trait에서 합치게 됩니다.
Welcome
클래스에서 Message
trait의 함수를 호출하게 되면 두 trait이 합쳐진 결과를 볼 수 있게 됩니다.
Trait method conlict resolution
Overriding Trait Method
클래스 내에서 여러 trait을 사용하게 될 때 이름이 같다면 fetal error
를 발생시키게 됩니다. 이는 insteadof
키워드를 사용하여 해결할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
trait Hello
{
public welcome()
{
echo "Hello world!!";
}
}
trait World
{
public welcome()
{
echo "Welcome!!";
}
}
class Welcome
{
use Hello, World{
Hello::welcome insteadof World;
}
}
$welcome = new Welcome();
$welcome->welcome();
// Hello world!!
Hello
와 World
trait모두 welcome
이름의 함수를 갖고 있습니다. 이 경우 inteadof
키워드를 사용하여 어떠한 trait의 함수를 사용할지 선언해 주어야 합니다.
위의 경우 Hello
trait의 함수를 사용하여 Hello world!!
가 출력되게 됩니다. 만약 Welcome
의 함수도 사용하고 싶다면 alias
를 지정해주면 됩니다.
Aliasing Trait Method
alias
는 as
키워드를 사용하여 지정해 줄 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php
trait Hello
{
public welcome()
{
echo "Hello world!!";
}
}
trait World
{
public welcome()
{
echo "Welcome!!";
}
}
class Welcome
{
use Hello, World{
World::welcome as secondWelcome;
Hello::welcome insteadof World;
}
}
$welcome = new Welcome();
$welcome->welcome(); // Hello world!!
$welcome->secondWelcome(); // Welcome!!
Reference
- https://www.lesstif.com/laravelprog/trait-26083451.html
- https://www.php.net/manual/en/language.oop5.traits.php
- https://www.w3schools.com/php/php_oop_traits.asp
- https://www.phptutorial.net/php-oop/php-traits/