라라벨이 애용하는 ::class 톺아보기

라라벨을 처음 개발할 때 라라벨 공식 문서를 보면 config/app.php을 보면 수많은 ::class를 볼 수 있습니다. 반면 엘로퀀트 모델에서는 같은 내용을 홑따옴표를 사용합니다.

<?php

'providers' => [
    /*
    * Laravel Framework Service Providers...
    */
    Illuminate\Auth\AuthServiceProvider::class,
    Illuminate\Broadcasting\BroadcastServiceProvider::class,
    Illuminate\Bus\BusServiceProvider::class,
    ...
<?php

public function phone()
{
    return $this->hasOne('App\Phone');
}

물론 위의 'App\Phone'Phone::class로 바꾸어도 같으며, 개발자 성향에 따라서 따옴표를 쓰거나 ::class를 쓸 수 있습니다.

이 둘은 완벽히 같지만, 그래도 다른 무언가가 있을 것 같습니다.

php.net 공식홈페이지에서 워낙 간단하게 설명이 되어서 가볍게 관련 내용을 정리 해 보겠습니다.

::class의 타입

::class는 php.net 공식문서에는 클래스 이름을 해석할 때 사용된다고 되어 있습니다. 그리고, 출력은 string 타입의 FQN(fully qualified name)이며, ClassName::class 형식이라고 되어 있고요.

타입을 알아보기 위해서 간단한 코드를 실행 해 봅시다.

<?php

var_dump(NumberFormat::class);

// output
// string(12) "NumberFormat"

공식문서의 설명대로 잘 나오네요.

말하자면, 'NumberFormat'이라는 문자열과 NumberFormat::class는 완벽히 같습니다! 네임스페이스가 있다면 네임스페이스까지 나옵니다.

Try\

그럼 몇가지 실험을 해 보죠.

<?php

namespace Cable8mm\Example;

var_dump(SampleClass::class);

// output
// string(28) "Cable8mm\Example\SampleClass"

실제 SampleClass는 없습니다. ::class는 실제로 클래스가 있는지를 체크하지 않는다는 것을 알 수 있습니다.

<?php

namespace Cable8mm\Example;

class A {
    public static function a() : string
    {
        return __CLASS__;
    }

    public static function b() : string
    {
        return self::class;
    }

}

echo A::a() . PHP_EOL;
echo A::b() . PHP_EOL;

// output
// Cable8mm\Example\A
// Cable8mm\Example\A

PHP에는 클래스 이름을 얻을 수 있는 또 다른 마법 상수(magic constant)인 __CLASS__도 같은 문자열을 출력해 줍니다.

상속과 trait에선?

조금만 더 깊게 들어가 봅시다.

상속 :

<?php

namespace Cable8mm\Example;

class A {
    public function a() : string
    {
        return __CLASS__ . PHP_EOL 
        . self::class . PHP_EOL 
        . static::class . PHP_EOL ;
    }
}

class B extends A {}

echo (new A)->a() . PHP_EOL;
echo PHP_EOL;
echo (new B)->a() . PHP_EOL;

// output
// Cable8mm\Example\A
// Cable8mm\Example\A
// Cable8mm\Example\A
//
// Cable8mm\Example\A
// Cable8mm\Example\A
// Cable8mm\Example\B

상속을 받은 클래스에서 static::class만 B 클래스를 리턴하는군요.

Traits:

<?php

namespace Cable8mm\Example;

trait T {
    public function a() : string
    {
        return __TRAIT__ . PHP_EOL 
            . __CLASS__ . PHP_EOL 
            . self::class . PHP_EOL 
            . static::class;
    }
}

class A {
    use T;
}

echo (new A)->a() . PHP_EOL;

// output
// Cable8mm\Example\T
// Cable8mm\Example\A
// Cable8mm\Example\A
// Cable8mm\Example\A

trait에서도 잘 작동하는 것을 알 수 있습니다.

다시 라라벨로

라라벨의 코드를 리뷰 해 보면 클래스의 FQN을 얻기 위해서 거의 모든 코드에는 ::class를 사용하고 있습니다.

반면 엘로퀀트 모델의 관계를 정의할 때에는 string을 직접 넣도록 공식 문서의 가이드에 나와 있습니다.

왜 그런걸까요?

제 생각에는 보통 관계를 ::class를 넣을 때는 IDE에서 자동으로 use를 넣어주고, 인자에는 클래스 이름만 들어가게 됩니다. 이렇게 말이죠.

<?php

use App\Phone;

public function phone()
{
    return $this->hasOne(Phone::class);
}

문제는 모델의 클래스 이름과 동일한 이름의 클래스 이름이 존재할 경우 IDE에서 넣어주는 클래스 경로가 잘못 들어갈 가능성이 있다는 사실입니다.

특히 라라벨의 규격상 모델의 이름과 리소스(JsonResource)의 이름은 공문조차도 동일하게 가이드되어 있습니다.

전 네이밍 규칙은 같은 프로젝트에서는 하나만 존재해야 한다고 생각합니다.

지금까지 ::class를 이용해서 관계를 정의했는데요, 다음 프로젝트에서는 어떻게 할지 약간의 고민을 하고 있습니다.

오늘도 즐거운 라라벨 생활 되시기 바랍니다.

Last updated

Was this helpful?