Skip to content
isdnetworks
Go back

속성처럼 쓴 메서드

(수정됨)

값을 읽었는데 예상과 다른 것이 나왔고 그런데도 오류는 나지 않았다. 항목이 분명히 다섯 개인데 $items->count 를 읽으면 0 이 나오고 있었다.

Table of contents

Open Table of contents

원인 — 값이 아닌 것을 읽은 이유

count() 는 메서드인데 그것을 속성처럼 접근하고 있었다. 그러면 존재하지 않는 속성이므로 null 이 되고 숫자로 쓰이는 자리에서 0 이 된다.

괄호를 붙여 $items->count() 로 하니 제대로 된 값이 나왔다. 문제는 없는 속성을 읽어도 예외가 안 나고 Undefined property 경고만 난다는 점이었다.

꺼져 있던 경고

error_reporting 을 확인하니 E_NOTICE 와 E_WARNING 을 둘 다 꺼 두고 있었다. E_ALL 로 다시 켜니 문제의 자리가 속성 이름과 함께 바로 출력됐다.

경고를 끄면 이런 것이 조용히 지나가고 오류 대신 틀린 값이 남는다. 개발 환경에서 전부 켜니 경고가 수백 개 나왔고 한 번에 다 고칠 수는 없었다.

판단 기준 — 위험도로 나눈 처리 순서

전부 한 번에 고치려니 위험한 것과 아닌 것이 섞여서 진도가 나가지 않았다. 그래서 성격에 따라 세 종류로 나눴다.

값이 틀리게 나오는 것과 동작에 영향이 없는 것과 E_DEPRECATED 문법 경고다. 없는 속성 접근은 값이 틀리게 나오므로 먼저 고쳤고 문법 경고는 판을 올릴 때 같이 하기로 했다. 분류하고 나서 첫 종류만 그 주에 끝냈고 나머지는 목록에 두고 차례로 했다.

운영에서의 설정

운영 환경에는 두 가지 방법이 있었는데 개발과 같이 display_errors 까지 켜는 것과 error_reporting 은 켜되 display_errors=Off 와 log_errors=On 으로 로그에만 남기는 것이다. 뒤쪽을 골랐다. 이유는 PHP 매뉴얼이 운영에서는 표시 대신 로깅을 쓰라고 강하게 권하고 php.ini-production 도 그렇게 돼 있어서다. 대신 경고가 났다는 것을 화면에서 바로 알 수 없어 로그를 주기적으로 세어야 하는 것을 감수했다.

끄면 문제를 알 수 없고 화면에 보이면 안쪽 사정이 밖으로 나가기 때문이다. 로그에서 종류별로 세어 보니 한 자리에서만 수천 건 나는 것이 있었고 그것부터 고쳤다.

해결 — 미리 잡는 쪽으로

로그에서 사후에 보는 것보다 PHPStan 으로 미리 잡는 쪽이 훨씬 빨랐다. 같은 것을 실행 전에 잡아 주므로 CI 에 붙여서 새로 들어오는 것까지 막았다.

반환 타입을 명시하니 분석 도구가 더 잘 잡았고 자주 쓰는 것은 메서드로 감싸서 호출하는 쪽에서 괄호를 빠뜨릴 자리를 없앴다. 괄호 없이 쓴 비슷한 실수를 grep -rn '->count[^(]' 로 찾으니 열 곳 남짓 더 나와서 전부 고쳤다.

정리


Share this post on:

Previous Post
앞 단계에서 이미 받아 둔 것
Next Post
검사가 실제로 검사하고 있는지 확인하는 법