PHP 스크랩

강좌라기엔 좀 그렇구 PHP에 대한 정보들을 스크랩해 놓은 개인 공간입니다. 타사이트에 있는 컨텐츠들에 대해서는 출처를 기재할테지만.. 문제가 된다면 말씀해 주세요~
공개
2016.05.31 23:56:06
조회수 38.6k 등록일 2016.07.16 17:48:19

여전히 PHP가 천덕꾸러기라고 생각하는 사람도 많다. 하지만 다른 언어에서만 볼 수 있었던 좋은 도구와 라이브러리, 의존성 관리도 지원하기 시작했고, PSR을 기준으로 표준도 활발하게 논의되고 있어 예전의 PHP 개발과는 확실히 분위기가 다르다. 

한국 내 커뮤니티에서 laravel, symfony와 같은 프레임워크를 쓰는 경우나 XE와 같이 이런 프레임워크를 기반으로 개발한 웹어플리케이션이 보이기 시작했지만 여전히 대부분 “Classic” PHP로 개발하고 있는 것은 분명 아쉬운 부분이다. 


좋은 도구가 있는데도 아무도 활용하지 않는다면, 그럴수도 있지 하고 지나치기엔 너무나도 슬픈 일이다. 좋은 기능을 도입하지 않는 사람들이 바로 PHP를 천덕꾸러기로 방치하고 있는 사람들이다.

Classic PHP의 모습

PHP를 사용해 예전 방식으로만 개발하는데 수많은 이유가 있을 수 있다. 물론 여기서 얘기하려는 편리한 새 기능이 내년, 혹은 그 후에 추가될 기능이라면 관심을 뒤로 미뤄도 할 말이 없다. 하지만 autoloadnamespace 문법, composer를 사용하는 것 등은 지금 당장 사용할 수 있는 것이기 때문에 더이상 미룰 수 없고 또한 미뤄서는 안된다. 

최신 기술이 아니라 이미 널리 사용되고 있고, 이제는 사용하지 않으면 안되는 기술이다. 지금 배워서 지금 사용해야 한다. 만약 지금 안쓰고 있다면 당신만 안쓰고 있는 것이다. 회사에서 사용하지 않고 있다면 먼저 배워서 알려줘라. 그만큼 중요하다.


그래서 PHP 개발자라면 2016년에는 놓치지 말고 해야 할 것들을 정리하려고 한다. 여기서 다루는 PHP 이야기는 먼 미래의 꿈이 아니라 현재 사용 가능하며, 또 해야만 하는 것들에 대한 이야기다. PHP 개발을 하고 있는데도 이 내용 중 하나라도 놓치고 있는게 있다면 꼭 알아보고 2016년엔 꼭 써먹어야 한다. 글 내내 중요하다는 이야기를 반복해서 하는 것은 정말 중요하기 때문이다. 그리고 이 글에서는 깊은 이야기를 다루진 않고 피상적인 부분만을 정말 간단하게 이야기하려고 노력했다. 이 포스트에 걸려있는 링크와 키워드로 더 깊은 내용을 찾아봤으면 좋겠다.

PHP 업그레이드 하기

PHP는 6 버전을 건너뛰고 7.0을 출시해서 현재 7.0이 최신 버전이다. PHP의 버전은 지속적으로 지원 패치를 제공하는 버전이 있고 보안 문제에 대해서만 패치를 제공하는 버전이 있다. PHP 버전 지원 페이지에서 지원 상황을 확인할 수 있다.

지금 사용하고 있는 PHP의 버전은 몇 버전인지 확인하자. 5.4를 사용하고 있다면 2015년 10월 이후로 보안 패치도 제공되지 않는, 유통기한 지난 버전을 사용하고 있는 것이다. 유통기한 지난 우유를 계속 마실 것인가? 만약 지금 사용하는 버전이 5.3이라면 이미 당신의 웹사이트는 그 누구도 안전하다고 말할 수 없다. 5.5 버전도 앞으로 6개월 후, 즉 2016년 7월이면 보안패치를 제공하지 않는다. 지금 적어도 7.0, 최소한 5.5로 변경해야 한다. 만약 레거시로 인해 업데이트 이후 문제가 발생한다고 방치하고 있다면, 사실 그 사이트는 이미 위험한 웹사이트다. 언제, 어느 순간에 DDoS 공격에 활용될 지 아무도 모른다. 악성코드 배포처로 활용되거나, 최악의 경우 내부의 데이터를 볼모로 협박 메일을 받을지도 모른다.

0순위가 되어야 할 보안 문제에도 의사결정권자가 마음을 움직이지 않고 오래된 버전을 고수한다면 속도가 더 빠르다는 점을 강조하자. 새버전의 PHP는 구버전에 비해 속도도 점점 빨라지고 메모리 사용량은 점점 줄어들고 있다. 5.6도 과거 버전에 비해 많이 빨라진 속도를 보여줬지만 7.0은 더 빨라졌다.

버전을 올리기만 하면 더 좋은 기능을 쓸 수 있는 것은 물론, 속도가 빨라지고 보안성이 높아진다. 이 단순한 일을 하지 않는건 게으름 외에는 답이 없다. 레거시가 걱정이라면 changelog를 찾아보고, 최소한 테스트라도 해보자. 서버호스팅을 사용하고 있다면 상위 버전의 PHP를 설치하고 웹호스팅을 사용하고 있다면 호스팅 업체에 문의하자. 아직도 5.3만 지원하는 호스팅이라면 당장 옮겨야 당신의 웹사이트가 안전하다.

Composer 사용하기

Composer는 PHP를 위한 의존성 관리 도구다. Python에서 pip, nodeJS에서 npm, Ruby에서 bundle, .Net에서 Nuget을 사용해본 적이 있다면 바로 그 역할을 하는 도구다. 리눅스를 사용해본 경험이 있다면, 필요한 도구를 “어디선가” 내려받는 apt-get이나 yum 같은 명령어를 최소한 복사-붙여넣기로 사용해봤을 것이다.

위로 든 예를 단 하나라도 써보지 않아 무슨 말을 하는지 모르겠다면, 내가 필요로 하는 기능의 PHP 라이브러리나 패키지를 스마트폰 앱스토어 같은 곳에서 다운로드 받는다고 생각해보자. 각각의 기능을 다운로드 받아 원하는 기능만 조합하는 방법으로 웹사이트, 웹서비스를 개발할 수 있다.

PHP 웹사이트에서 이메일을 보낼 때 mail() 함수로 보내고 있다면, 매번 지저분한 header를 직접 작성하고, HTML을 직접 변수에 넣어 보내는 지저분한 일을 해본 경험이 있을 것이다. 거기에 첨부파일도 넣어 보내본 경험이 있다면 얼마나 쉽게 난장판이 되는지 알 수 있다. composer를 사용한다면 이런 문제를 깔끔하게 해결할 수 있는 멋진 PHP 패키지를 설치해서 활용할 수 있다. nette/mail로 메일을 쉽게 구성하고, league/plates와 같은 깔끔한 템플릿 엔진을 단 한 줄의 설치 명령어로 바로 사용할 수 있게 된다.


composer를 사용하라고 하는 이유는 단순히 이 도구를 사용하는 과정을 배우는 것으로도 더 나은 개발을 시작할 수 있는 좋은 출발점이 되기 때문이다. composer를 제대로 사용하기 위해서는 기본적으로 namespaceautoload에 대해 이해해야 한다. 더 나아가 객체지향과 같은 개발 페러다임을 이해하는데 좋은 시작점이 되고 의존성을 어떻게 관리하는지, 테스트를 어떻게 수행해야 하는지 등 현대적인 개발에 있어 필수적인 부분을 학습하는데 중요하다. 최근 작성되는 PHP와 관련된 글을 보면 기본적으로 composer를 사용하는 것으로 가정하고 작성되기 때문에 PHP 개발자에게 있어서 필수적으로 배워야 할 도구다.

PSR 준수하기

PHP 난개발로 인해 가장 고통 받았던 사람들은 다름 아닌 PHP 프레임워크/라이브러리 개발자다. 범용적인 기능으로 만들어도 자신의 라이브러리에서만 사용할 수 밖에 없던 이유는 공통된 규칙이 없기 때문이었다. 모두 각자의 방식대로 만드는게 일상이었던 PHP 환경에서, 프레임워크나 라이브러리를 만들던 사람들이 모여 프레임워크 운용 그룹(Framework Interop Group, FIG)을 만들었고, PHP의 표준적인 개발을 위한 PSR 문서를 만들었다.

PSR 문서는 PHP-FIG에서 확인할 수 있다. autoload, 인터페이스의 사용, 코딩 스타일 등 현재 수락된 문서와 진행중인 문서를 확인할 수 있다. 이 문서에서 제안하는 규칙을 따르는 것으로 같은 스타일의 코드를 유지하는데 도움이 된다. PHP 개발자를 채용할 때, “우리는 PSR을 준수해서 개발하고 있습니다.” 라는 한 마디로 어떤 스타일을 따르는지 설명할 수 있는 것이다.

앞서 언급한 composer도 PSR을 준수해서 만든 도구다. PSR에서 제시하는 방식대로 코드를 작성한다면 composer에서 다른 개발자가 작성한 코드를 내려받아 사용하는 것과 같이 당신의 라이브러리도 누구나 쉽게 사용할 수 있다. 모두에게 공개된 packagist는 서버 코드 또한 공개되어 있어서 사내 전용 packagist를 구성해 사용할 수도 있다. 이 모든 일이 PSR을 준수하고 composer를 사용하는 것으로 가능하다.

보너스: 현대적인 개발 패러다임 학습하기

PSR과 composer가 일궈놓은 환경은 이전까지 활용하기 어려웠던 디자인 패턴이나 개발 패러다임을 PHP에서 사용하도록 하는데 큰 도움을 주고 있다. Factory, Strategy와 같은 디자인 패턴의 활용, 단위 테스트나 행위 주도 테스트를 통한 개발, 서비스 코드 간의 의존적인 환경을 줄이기 위한 의존성 주입이나 ORM과 같은 데이터베이스 추상화 등은 더이상 다른 멋진 언어에서만 존재하는 것이 아니라 PHP에서도 현재 가능한 이야기다.

지금까지 대부분의 프레임워크는 자신들의 코드에 맞게 작성한, 그 프레임워크를 사용하지 않고서는 사용할 수 없는 코드만 제공해왔다면, 현대적인 PHP 개발에서는 누구든 쉽게 필요에 따라 꺼내서 쓸 수 있는 수많은 레고 블럭을 제공한다고 생각하면 된다. 개발 패러다임을 학습하는 것으로 이 수많은 패키지를 더 쉽게, 다시 활용할 수 있는 코드로 만드는데 도움이 된다. 다른 사람의 구현을 이해하는데도 도움이 되고 확장 가능하고 지속 가능한 코드를 작성하는데도 도움이 된다.

코드에서 문제가 발생할 때마다 print_r()exit(), 그리고 새로고침 키로 디버깅을 한 경험이 있을 것이다. 지금도 그렇게 개발하고 있어도 이해할 수 있다. 이제는 문제가 나타났을 때, 에러를 발생하고, 예외 처리를 하고, monolog/monolog와 같은 패키지로 깔끔하게 로그를 남겨 확인하면 된다. 복잡하고 크고 어려운 문제를 한번에 해소하려고 하는 것은 쉽지 않은 일이기 때문에 이런 작은 변화부터 시작되어야 한다. 다른 언어에서는 흔하게 사용하는 패러다임은 이미 많은 개발자가 편하게 활용할 수 있도록 수많은 패키지로 만들어 제공되고 있다. 배우고, 살펴보고, 활용하자.

이 글은 공상과학이 아니다. PHP 개발자라면서 여기서 다룬 이야기를 단 하나라도 이해하지 못했다면 정말로 반성하고 공부해야 한다. (취미로 하는 일이고, 집에 돈이 많다면 상관 안하겠지만.) 회사에서 PHP를 사용하는데 이런 이야기가 전혀 없었다면 사내 메일로 이 글을 뿌리고, 인트라넷에 공유하고, 출력해서 화장실 칸마다 붙이고, 당장에 스터디를 꾸려 배워야 한다. 이 글을 읽고 현대적인 PHP에 대해 공부하고 싶어졌다면 감사하게도 PHP The Right Way 한국어판이 있어 이 글에서 시작하는 것으로 충분하다. 좋은 커뮤니티도 학습에 있어 중요한 요소다. 모던 PHP 유저 모임에 가입해 공유되는 다양한 글을 읽어보고 세미나에도 참여해보자.

이 글을 읽은 PHP 개발자라면, 2016년엔 꼭 복붙된 PHP 코드와 include로 범벅된 PHP 코드에서 벗어나고, 더 나은 추상화와 질서정연한 코드 속에 즐겁게 개발할 수 있기를 기도한다.


조회수 31.9k 등록일 2016.06.01 00:01:05

가끔 PHP로 웹페이지를 작성할 일이 있는데, 유용한 팁을 우연히 보게 되어 한글로 옮겨적어본다.

원문: Reinhold Weber씨의 40 Tips for optimizing your php Code

  1. 메쏘드가 static이 될 수 있다면 static으로 선언하라. 4배 빨라진다.
  2. echo가 print보다 빠르다.
  3. 문자열을 이어붙이지 말고, echo를 이용하여 여러 개의 파라미터를 적어라.
  4. for 루프을 위핸 최대값(탈출조건)을 루프 안에서가 아니고 루프 시작 이전에 지정하라.
  5. 메모리를 해제하기 위해 변수를 unset하라. 특히 커다란 배열은 그래야 된다.
  6. get, set, __autoload와 같은 마법을 피해라.
  7. require_once()는 비싸다.
  8. include와 require를 사용할 때, 경로를 찾는데 시간이 적게 걸리는 full path를 사용하라.
  9. 스크립트가 언제 실행했는지 알고 싶으면 time()보다 $_SERVER['REQUEST_TIME']이 좋다.
  10. 정규표현식보다는 가능하면 strncasecmp나 strpbrk, stripos를 사용하라.
    1. 역주
    2. strncasecmp: 두 문자열의 앞쪽 일부가 대소문자 구분없이 일치하는지 확인할 때 사용
    3. strpbrk: 문자 집합에 속한 특정 문자가 문자열에 나타나는지 확인할 때 사용
    4. stripos: 대소문자 구분없이 특정 문자열이 다른 문자열에 포함되는지 확인할 때 사용
  11. str_replace가 preg_replace보다 빠르지만, strtr은 str_replace보다 4배 빠르다.
  12. 만약 문자열 교체 같은 함수가 배열과 문자열을 인자로 받아들이면, 그리고 그 인자 리스트가 길지 않다면, 배열을 한 번에 받아들여서 처리하는 것 대신에 한 번에 문자열을 하나씩 넘겨서 처리하는 것을 고려해봐라.
  13. 여러 개의 if/else if 문장 대신에 select 문장을 사용하는 게 더 좋다.
  14. @를 이용한 에러 출력 방지는 매우 느리다.
  15. Apache의 mod_deflate를 켜라.
    1. 역주
    2. mod_deflate는 서버의 출력을 클라이언트에게 보내기 전에 압축하는 모듈임
  16. DB를 다 사용했으면 연결을 닫아라.
  17. $row['id']가 $row[id]보다 7배 빠르다.
  18. 에러 메시지는 비싸다.
  19. for 루프의 표현식 안에서 함수를 사용하지 마라. for ($x = 0; $x < count($array); $x)에서 count() 함수가 매번 호출된다.
  20. 메쏘드 안에서 지역 변수를 증가시키는 것이 거의 함수 안에서 지역 변수를 호출(증가?)하는 것만큼 빠르다.
  21. 전역 변수를 증가시키는 것이 지역 변수를 증가시키는 것보다 2배 느리다.
  22. 객체의 멤버변수를 증가시키는 것이 지역 변수를 증가시키는 것보다 3배 느리다.
  23. 값이 지정되지 않은 지역 변수를 증가시키는 것이 미리 초기화된 변수를 증가시키는 것보다 9~10배 느리다.
  24. 전역 변수를 함수 안에서 사용하지 않으면서 그저 선언하기만 해도 (지역 변수를 증가시키는 것만큼) 느려진다. PHP는 아마 전역 변수가 존재하는지 알기 위해 검사를 하는 것 같다.
  25. 메쏘드 호출은 클래스 안에서 정의된 메쏘드의 갯수에 독립적인 듯 하다. 왜냐하면 10개의 메쏘드를 테스트 클래스에 추가해봤으나 성능에 변화가 없었기 때문이다.
  26. 파생된 클래스의 메쏘드가 베이스 클래스에서 정의된 것보다 더 빠르게 동작한다.
  27. 한 개의 매개변수를 가지고 함수를 호출하고 함수 바디가 비어있다면(함수 내부에서 아무것도 실행하지 않는다면) 그것은 7~8개의 지역변수를 증가시키는 것과 똑같은 시간을 차지한다. 비슷한 메쏘드 호출은 마찬가지로 15개의 지역변수를 증가시키는 연산쯤 된다.
  28. 문자열을 이중 따옴표 대신에 단일 따옴표로 둘러싸는 것은 좀 더 빠르게 해석되도록 한다. 왜냐하면 PHP가 이중 따옴표 안의 변수를 찾아보지만 단일 따옴표 안에서는 변수를 찾지 않기 때문이다. 물론 문자열 안에서 변수를 가질 필요가 없을 때만 이렇게 사용할 수 있다.
  29. 문자열을 echo할 때 마침표 대신에 쉼표로 분리하는 것이 더 빠르다.
  30. 주의: 이것은 여러 문자열을 인자로 받아들이는 함수인 echo로만 작동한다.
  31. Apache에 의해 PHP 스크립트는 정적 HTML 페이지보다 최소 2에서 10배 느리게 서비스된다. 더 많은 정적 HTML 페이지와 더 적은 스크립트를 사용하려고 노력하라.
  32. PHP 스크립트는 캐시되지 않으면 매번 재 컴파일된다. 컴파일 시간을 제거함으로써 25~100%만큼의 성능을 증가시키기 위해 PHP 캐싱 도구를 설치하라.
  33. 가능한 한 많이 캐시하라. memcached를 사용하라. memcached는 고성능 메모리 객체 캐싱 시스템이다.
  34. 문자열을 가지고 작업하며 문자열이 특정 길이인지 확인할 필요가 있을 때, strlen() 함수를 쓸 것이다. 이 함수는 계산없이 zval 구조체에서 사용할 수 있는 이미 알려진 문자열 길이를 반환하기 때문에 매우 빠르다. 그러나 strlen()이 함수이기 때문에 여전히 조금 느리다. 왜냐하면 함수 호출은 언급된 함수의 실행 뒤에 lowercase와 hashtable lookup같은 여러 개의 연산을 호출하기 때문이다. 어떤 경우에는 isset() 트릭을 이용하여 코드의 스피드를 증가시킬 수도 있다
    if (strlen($foo) < 5) { echo "Foo is too short"; }
    if (!isset($foo{5})) { echo "Foo is too short"; }
    1. isset()을 호출하는 것은 strlen()과는 달리 isset()이 언어 기본문법이고 함수가 아니기 때문에 함수 찾와 lowercase 작업을 필요로 하지 않으므로 strlen()보다 더 빠를 수도 있다. 이것은 가상적으로 문자열의 길이를 결정하는 실제 코드에 과부하가 없다는 것을 의미한다.
  35. 변수 $i의 값을 증가시키거나 감소키킬 때, $i++은 ++$i보다 조금 더 느릴 수 있다. 이것은 PHP의 특징이고 다른 언어에는 해당되지 않으니 좀 더 빨라질 것을 기대하면서 C나 Java 코드를 바꾸러 가지 마라. 안 빨라질 것이다. ++$i는 PHP에서 좀 더 빠른데 그것은 $i++에 4개의 opcode가 사용되는 대신에 3개만 필요하기 때문이다. 후증가는 사실 증가될 임시변수의 생성을 초래한다. 반면에 전증가는 원래 값을 직접 증가시킨다. 이것은 opcode가 Zend의 PHP optimizer처럼 최적화하는 최적화 기법의 하나이다. 모든 opcode optimizer들이 이 최적화를 수행하는 것은 아니고 많은 ISP와 server들이 opcode optimizer없이 수행되고 있기 때문에 명심하는 게 좋을 것이다.
  36. 모든 것이 OOP일 필요는 없다. 종종 그것은 너무 많은 과부하가 된다. 각각의 메쏘드와 객체 호출은 메모리를 많이 소비한다.
  37. 모든 데이터 구조를 클래스로 구현하지 마라. 배열도 유용하다.
  38. 메쏘드를 너무 많이 분리하지 마라. 어떤 코드를 정말 재사용할지 생각해봐라.
  39. 항상 메쏘드의 코드를 나중에 필요할 때 분리할 수 있다.
  40. 수많은 미리 정의된 함수를 활용해라.
  41. 매우 시간을 소비하는 함수가 있다면, C 확장으로 작성하는 것을 고려해봐라.
  42. 당신의 코드를 프로파일해봐라. 프로파일러는 코드의 어떤 부분이 가장 많은 시간을 소비하는지 보여준다. Xdebug 디버거는 이미 프로파일러를 포함하고 있다. 프로파일링은 전체적인 병목을 보여준다.
  43. Apache 모듈로 사용가능한 mod_gzip은 실행 중에 데이터를 압축하여 전송할 데이터를 80%까지 줄일 수 있다.
  44. John Lim의 PHP를 최적화하는 것에 관한 뛰어난 글