연관 배열을 반환하지 마십시오!

7263 단어 phpoopbeginners
나는 클라이언트 코드를 작성할 때 연관 배열을 다루는 것을 싫어합니다. 그만큼
배열의 문제는 컨텍스트가 없다는 것입니다. 특별한 지식은 없습니다. 일반적으로 불편한 형식으로 패키징된 데이터일 뿐입니다. 최악의 부분은 그들이 나를 특정 구현에 묶는 것입니다.

이제 균일한 데이터가 있는 배열을 반환해서는 안 된다는 뜻이 아닙니다. 특정 유형의 객체 배열을 반환하는 것은 괜찮습니다(ish). API를 통해 특정 유형의 데이터만 포함할 것이라고 여전히 약속할 수는 없지만.

배열은 일부 클래스에 대한 데이터의 내부 표현으로 작동할 수 있지만 내부적으로 유지되어야 하는 방식입니다.

내가 말하는 것은 하드코딩된 문자열을 키로 사용하는 불쾌한 다차원 배열입니다.

이걸 고려하세요:

class AcmeFileSender implements FileSender
{
    public function sendFiles(FileCollection $files): array
    {
        $sent = 0;
        $errors = [];
        foreach ($files as $file) {
            try {
                $this->send($file);
                $sent++;
            } catch (SenderException $exception) {
                $errors[] = $exception->getMessage();
            }
        }
        return [
            "sent" => $sent,
            "failed" => count($errors),
            "errors" => $errors
        ];
    }

    public function send(File $file): void {//...}
}


그렇게 나빠 보이지 않습니까? 연관 배열에 있는 세 개의 키 값일 뿐입니다.

이 경우 문제는 배열이 구조에 대해 아무 것도 약속할 수 없다는 것입니다. 이것은 우리가 클라이언트 코드를 작성할 때 sendFiles() 의 구현에 의존한다는 것을 의미합니다. 우리는 키가 무엇인지, 그 키 뒤에 어떤 종류의 데이터가 있는지 정확히 알아야 합니다.

OOP에서는 다른 클래스의 구현 세부 사항에 대해 걱정할 필요가 없습니다. 우리는 인터페이스에만 관심이 있습니다.

최근에 나는 훨씬 더 심각한 범죄를 저지를 수 있는 일에 부딪쳤습니다.

public function processStuff($stuff): array
{
    //...
    return [$someArray, $someObject];
}

//... in client code
list($someArray, $someObject) = $this->processor->processStuff($stuff);


자, 사적인 방법에서 이런 종류의 혐오스러운 것을 반환하는 것은 한 가지입니다. 그러나 이와 같이 공개 API를 설계하기 시작하면 모든 희망이 사라집니다. 이것은 당신이 절차적 코드 기반을 다루고 있다는 거의 죽은 대가입니다. 절차적 코드 기반에서 모든 것은 데이터이며 조작될 수 있습니다.

위의 경우 문제는 컨텍스트의 부족입니다. someArraysomeObject를 함께 받는다는 것은 무엇을 의미합니까? 함께 돌아온 이유는? processStuff()의 구현은 그것이 어떻게 사용되는지 알고 있다는 것이 분명합니다. 따라서 일부 클라이언트 코드와 함께 접착되는 것만큼 실제로 설계되지 않았습니다. 클라이언트 코드는 processStuff() 구현과 매우 밀접하게 연결되어 있습니다.

많은 경우 책임을 정의하는 방법에 대해 혼란이 있습니다. 코드는 무언가를 수행하고 클라이언트에게 성공에 대한 일부 표시를 반환합니다. 클라이언트와 서버 사이에 신뢰가 별로 없습니다. 클라이언트는 서버의 작업 품질에 대해 편집증적입니다.

첫 번째 예를 더 좋게 만들기 위해 우리는 무엇을 할 수 있습니까? 값 개체. sendFiles() 값 개체를 사용하면 훨씬 더 표현력이 좋습니다.

interface SenderReport
{
    public function sent(): int;
    public function failures(): int;
    public function errors(): Iterator;
    public function print(): string;
}


우리는 FileSender와 그 구현을 업데이트할 것입니다.

class AcmeFileSender implements FileSender
{
    //...
    public function sendFiles(FileCollection $files): SenderReport
    {
        //...
        return new FileSenderReport($sent, count($errors), $errors);
    }
}


이제 우리는 SenderReport 의 구현을 고통스럽게 인식하는 대신 FileSender::sendFiles() 의 인터페이스에 의존할 수 있습니다. 이제 컨텍스트가 있습니다. 또한 FileSender의 구현을 자유롭게 변경할 수 있습니다.

--

공개 API에서 연관 배열을 반환하지 마십시오. 정말로 값을 반환해야 하는지 평가하십시오. 그리고 필요한 경우 귀하와 귀하의 코드 사용자가 신뢰할 수 있는 인터페이스가 있는 항목을 반환하십시오.

좋은 웹페이지 즐겨찾기