Menu

PHP 면접 질문과 답변(PHP 8)

PHP 8 기준의 짧고 정확한 답이 달린 PHP 면접 질문 24개입니다. ==와 ===, isset과 empty부터 foreach의 참조, self와 static, 제너레이터, SQL 인젝션, 비밀번호 해싱까지 다룹니다. 대부분의 답에는 실행하고 바꿔 볼 수 있는 코드가 있습니다.

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

면접에서 가장 많이 나오는 PHP 질문들이며, PHP 8.3에서 정확한 짧은 답과 코드가 요점을 보여 주는 곳에는 코드를 달았습니다. Run을 누르기 전에 각 블록의 출력을 예측해 보세요. 면접관이 시험하는 것이 바로 그것입니다.

초급 PHP 면접 질문

PHP는 무엇이고 어떻게 실행되나요?

PHP는 서버 측 스크립트 언어입니다. 웹 서버(Nginx나 Apache)가 요청을 PHP(보통 PHP-FPM)에 넘기고, PHP가 스크립트를 위에서부터 실행하며, 출력한 것이 응답이 되고 보통 HTML입니다. 각 요청은 새로 시작합니다. 세션, 데이터베이스, 캐시에 저장하지 않으면 변수는 요청 사이에 살아남지 않습니다. PHP는 명령줄에서도 스크립트를 실행합니다(php script.php).

==와 ===의 차이는 무엇인가요?

==는 타입 저글링 후에 비교하고, ===는 변환 없이 값과 타입을 비교합니다. 위의 준비 운동이 ==의 동작을 보여 줍니다. 숫자 문자열은 숫자로 비교되므로 '10' == '1e1'은 true입니다. PHP 8부터 숫자와 숫자가 아닌 문자열은 문자열로 비교되므로 0 == 'a'는 false입니다(PHP 7에서는 true였습니다). 셀을 눌러 두 연산자를 비교해 보세요.

느슨한 비교(==)와 엄격한 비교(===)
Point at or tap a cell to read it as PHP.
$a == $btruefalse01"0""1"""null[]"a""10""1e1"
true
false
0
1
"0"
"1"
""
null
[]
"a"
"10"
"1e1"
Every cell computed by PHP 8.3.19.

기본적으로 ===를 쓰세요. in_array()와 array_search()는 세 번째 인수로 true를 넘기지 않으면 ==를 씁니다.

echo와 print의 차이는 무엇인가요?

둘 다 문자열을 출력합니다. echo는 인수를 여러 개 받고(echo $a, $b;) 아무것도 반환하지 않으며, print는 하나를 받고 1을 반환하므로 표현식 안에서 쓸 수 있습니다. 둘 다 함수가 아니므로 괄호는 선택입니다. 실제로는 모두 echo를 씁니다.

작은따옴표와 큰따옴표의 차이는?

큰따옴표 문자열은 변수와 이스케이프 시퀀스를 해석합니다: "Hi $name\n". 작은따옴표 문자열은 \'와 \\를 빼면 글자 그대로입니다: 'Hi $name\n'은 그 문자들을 정확히 출력합니다. 속도 차이는 무시할 만하므로 선택은 가독성의 문제입니다. 변수를 넣을 때는 큰따옴표, 아닐 때는 작은따옴표입니다.

PHP의 데이터 타입에는 무엇이 있나요?

스칼라 타입 네 가지(int, float, string, bool), 복합 타입 두 가지(array와 object), 특수 타입 두 가지(null과 resource)입니다. callable, iterable, mixed, void는 타입 선언으로만 존재하며 값의 타입이 되지는 않습니다. gettype()과 get_debug_type()은 실행 시점에 값의 타입을 알려 주고, var_dump()는 값과 함께 출력합니다.

isset, empty, is_null의 차이는 무엇인가요?

isset($x)는 변수가 존재하고 null이 아닐 때 true입니다. empty($x)는 변수가 존재하지 않거나 거짓으로 취급될 때(0, '0', '', [], false, null) true입니다. is_null($x)는 null에 대해 true이지만 정의되지 않은 변수에는 경고를 냅니다. isset과 empty는 경고를 내지 않으므로 배열 키에 씁니다.

$x의 각 값에 대한 isset, empty, is_null
Point at or tap a cell to read it as PHP.
$xissetemptyis_null
null
false
0
"0"
""
" "
[]
"a"
0.0
Every cell computed by PHP 8.3.19.

사람들이 틀리는 행은 "0"입니다. 문자열 0은 비어 있고, " "(공백)은 비어 있지 않습니다. 전체 표는 isset 페이지에 있습니다.

include와 require의 차이는 무엇인가요?

둘 다 다른 파일을 끼워 넣고 실행합니다. 파일이 없으면 include는 경고를 내고 스크립트를 계속하며, require는 Error("Failed opening required")를 던져 무언가가 잡지 않는 한 스크립트를 멈춥니다. _once 변형(include_once, require_once)은 이미 불러온 파일을 건너뛰어 "cannot redeclare function" 에러를 막습니다. 스크립트가 없이는 실행될 수 없는 파일, 즉 거의 모든 파일에는 require(또는 require_once)를 쓰세요. Composer의 오토로더가 대부분의 수동 포함을 불필요하게 만듭니다.

GET과 POST의 차이는 무엇인가요?

GET은 데이터를 URL의 쿼리 문자열($_GET)로 보내므로 보이고, 북마크할 수 있고, 길이가 제한됩니다. 검색과 페이지 나누기처럼 읽기에 쓰세요. POST는 데이터를 요청 본문($_POST)으로 보냅니다. 로그인, 저장, 결제처럼 상태를 바꾸는 모든 것에 쓰세요. 링크는 미리 불러와지고 크롤링되므로 GET 요청은 절대 데이터를 바꾸면 안 됩니다.

null 병합 연산자는 무엇인가요?

$a ?? $b는 $a가 존재하고 null이 아니면 $a를, 아니면 $b를 반환하며, 정의되지 않은 변수나 키에도 경고가 없습니다: $page = $_GET['page'] ?? 1;. ??=는 왼쪽이 null이거나 없을 때만 대입합니다. 모든 거짓 값에서 대체값으로 넘어가는 ?:와 다르므로 0 ?: 5는 5지만 0 ?? 5는 0입니다.

중급 PHP 면접 질문

foreach에서 참조로 반복하면 어떻게 되나요?

foreach ($arr as &$v)는 요소를 그 자리에서 수정하게 해 주지만, 반복문이 끝난 뒤에도 $v는 마지막 요소에 대한 참조로 남습니다. 두 번째 반복문에서 그 이름을 다시 쓰면 그 요소를 덮어씁니다.

마지막 요소는 30이 아니라 20입니다. 두 번째 반복문에서 $v(여전히 $arr[2])에 10, 그다음 20, 그다음 자기 자신이 대입됩니다. unset($v) 앞의 //를 지우고 다시 실행해 보세요. 참조는 foreach 페이지에서 자세히 다룹니다.

추상 클래스와 인터페이스의 차이는? 그리고 트레이트는 무엇인가요?

인터페이스는 계약입니다. 구현 없는 메서드 시그니처(와 상수)이며, 클래스는 여러 개를 구현할 수 있습니다. 추상 클래스는 속성, 생성자, 완성된 메서드에 더해 자식이 작성해야 하는 추상 메서드를 담을 수 있으며, 클래스는 하나만 상속합니다. 트레이트는 use로 클래스에 복사되는 메서드 묶음이며, 부모를 공유하지 않는 클래스 사이에서 코드를 재사용하기 위한 것입니다.

면접관이 좋아하는 짧은 답: 무엇을 할 수 있는지 말할 때는 인터페이스, 어떻게 하는지 공유할 때는 추상 클래스, 관련 없는 클래스에 같은 메서드 몇 개가 필요할 때는 트레이트를 씁니다.

self와 static의 차이는 무엇인가요?

self는 코드가 작성된 클래스를 가리킵니다. static은 실행 시점에 실제로 호출된 클래스를 가리키며, 이를 늦은 정적 바인딩이라고 합니다. "이런 종류의 객체"를 만들거나 설명하는 부모 메서드에서 중요합니다.

User::createStatic()은 User를 만듭니다. User::createSelf()는 Model을 만들어 static 반환 타입을 어기므로 PHP가 TypeError를 던집니다. 그래서 팩토리 메서드는 new static()을 씁니다.

매직 메서드는 무엇인가요?

PHP가 대신 호출하는 메서드이며, 모두 밑줄 두 개로 시작합니다. 흔한 것들: 객체가 만들어질 때 __construct(), 파기될 때 __destruct(), 문자열로 쓰일 때 __toString(), 접근할 수 없는 속성에 __get()과 __set(), 없는 메서드에 __call()과 __callStatic(), 객체를 함수처럼 호출할 때 __invoke(), clone 뒤에 __clone()입니다.

array_merge()와 + 연산자의 차이는 무엇인가요?

array_merge()는 덧붙입니다. 숫자 키는 다시 매겨지고 나중 문자열 키가 앞의 것을 덮어씁니다. +는 합집합입니다. 왼쪽 배열을 유지하고 없는 키만 추가하므로 키가 겹치면 첫 번째 값이 이깁니다.

+는 기본값에 맞는 도구입니다. $options + ['timeout' => 30]은 호출한 쪽이 넘긴 것을 유지하고 나머지를 채웁니다.

declare(strict_types=1)은 무엇을 하나요?

이것이 없으면 PHP는 가능할 때 스칼라 인수를 선언된 매개변수 타입으로 변환합니다. int 매개변수에 "5"를 넘기면 5가 됩니다. 파일의 첫 문장으로 declare(strict_types=1);을 두면 그 파일에서 하는 호출은 정확한 타입을 넘겨야 하고, 아니면 TypeError가 납니다(float 매개변수에 int를 넘기는 것이 유일하게 허용되는 확장입니다).

declare 줄을 지우고 다시 실행해 보세요. 두 번째 호출이 예외를 던지는 대신 10을 반환합니다.

세션과 쿠키의 차이는 무엇인가요?

쿠키는 브라우저에 저장되고 모든 요청과 함께 전송되므로 방문자가 읽고 바꿀 수 있습니다. 세션은 데이터를 서버에 저장하고 쿠키(PHPSESSID)에는 무작위 id만 둡니다. 로그인한 사용자 id처럼 신뢰해야 하는 것은 $_SESSION에 넣고, 로그인 후에는 session_regenerate_id(true)를 호출하세요. 코드는 세션과 쿠키 페이지에 있습니다.

SQL 인젝션은 어떻게 막나요?

입력을 연결해서 SQL을 만들지 마세요. 값이 쿼리와 따로 전송되도록 prepared statement를 쓰세요.

<?php
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ?');
$stmt->execute([$email]);
$user = $stmt->fetch();

자리 표시자는 값에만 동작합니다. 테이블 이름, 컬럼 이름, ASC/DESC는 SQL에 들어가기 전에 허용 목록과 대조해야 합니다. PDO를 참고하세요.

XSS는 어떻게 막나요?

입력이 아니라 출력을 이스케이프하세요. HTML에 출력하는 모든 값을 htmlspecialchars($value, ENT_QUOTES, 'UTF-8')로 감싸거나, 그것을 자동으로 하는 템플릿 엔진(Twig, Blade)을 쓰세요. <script> 안에서는 JSON_HEX_TAG와 함께 json_encode()를 쓰세요. 두 번째 방어선으로 Content-Security-Policy 헤더를 추가하세요.

비밀번호는 어떻게 저장해야 하나요?

password_hash($password, PASSWORD_DEFAULT)로 저장하고 password_verify($password, $hash)로 확인합니다. 해시 안에 저장되는 무작위 솔트와 의도적인 cost를 가진 bcrypt(또는 Argon2id)를 씁니다. md5()와 sha1()은 빠르고 솔트가 없으므로 비밀번호에는 맞지 않습니다. 로그인 때 password_needs_rehash()로 예전 해시를 업그레이드하세요.

고급 PHP 면접 질문

제너레이터는 무엇이고 언제 쓰나요?

yield가 든 함수는 요청될 때만 값을 하나씩 만드는 Generator를 반환합니다. 메모리에 배열을 만들지 않고 크거나 끝없는 시퀀스를 반복할 수 있게 해 줍니다.

대표적인 용도는 큰 파일을 한 줄씩 읽기, 데이터베이스 행 스트리밍, 지연 파이프라인입니다. 제너레이터는 키(yield $key => $value), 위임(yield from), send()로 값 받기도 지원합니다.

클로저는 무엇이고 use는 무엇을 하나요?

익명 함수(function () { ... })는 Closure 객체입니다. use에 나열하지 않으면 바깥 변수를 보지 못하며, use는 클로저가 만들어지는 순간의 값을 복사합니다. use (&$x)는 대신 참조로 캡처합니다. 화살표 함수(fn ($x) => $x * $factor)는 바깥 변수를 값으로 자동 캡처하고 표현식 하나를 담습니다.

abstract, final, readonly의 차이는 무엇인가요?

abstract는 인스턴스를 만들 수 없는 클래스나 자식이 구현해야 하는 메서드를 표시합니다. final은 메서드 오버라이드나 클래스 상속을 금지합니다. readonly(PHP 8.1)는 속성을 클래스 안에서, 보통 생성자에서 한 번만 쓸 수 있게 합니다. PHP 8.2는 모든 속성이 readonly인 readonly 클래스를 추가했습니다.

Composer는 무엇이고 PSR-4는 무엇인가요?

Composer는 PHP의 의존성 관리자입니다. composer.json은 패키지를 나열하고, composer.lock은 정확한 버전을 고정하며, vendor/autoload.php가 모든 것을 불러옵니다. PSR-4는 네임스페이스 접두사를 폴더에 대응시키는 오토로딩 표준이므로 App\Mail\Mailer는 src/Mail/Mailer.php에 있고 처음 쓸 때 불러와집니다. install(lock 파일에서)과 update(새 버전, 새 lock 파일)의 차이를 설명하세요.

PHP 8에서 무엇이 바뀌었나요?

핵심 기능입니다. 8.0에서는 이름 있는 인수, match, nullsafe 연산자 ?->, 유니언 타입, 생성자 속성 승격, 어트리뷰트, str_contains(), 더 합리적인 문자열과 숫자 비교. 8.1에서는 enum, readonly 속성, 일급 callable 문법(strlen(...)), 파이버. 8.2에서는 readonly 클래스와 독립적인 null/true/false 타입. 8.3에서는 타입이 있는 클래스 상수, #[\Override] 어트리뷰트, json_validate(). 8.4에서는 프로퍼티 훅, 비대칭 접근 제어(public private(set)), array_find(), 감싸는 괄호 없는 new Foo()->method(). 많은 함수가 이제 경고와 함께 false를 반환하는 대신 TypeError나 ValueError를 던집니다.

PHP는 메모리를 어떻게 관리하나요?

모든 값에는 참조 카운트가 있고, 0이 되면 메모리가 즉시 해제됩니다. 서로를 참조하는 순환 객체는 절대 0에 닿지 않으므로, 가능한 순환 루트의 버퍼가 가득 찰 때마다(기본 10,000개) 순환 수집기가 실행되어 해제합니다(gc_collect_cycles()는 요청 시 실행합니다). 배열과 문자열은 쓰기 시 복사입니다. $b = $a를 대입하면 둘 중 하나가 수정될 때까지 데이터를 공유합니다. 각 요청이 깔끔하게 시작하고 끝나므로 메모리 누수는 주로 오래 실행되는 워커와 큐 소비자에서 문제가 됩니다.

PHP 배열은 어떻게 구현되어 있나요?

PHP 배열은 순서 있는 해시 맵입니다. 삽입 순서를 유지하고 int나 string 키를 값에 대응시키며, 그래서 같은 타입이 리스트, 딕셔너리, 스택으로 쓰입니다. 키 조회(isset($arr[$key]))는 평균 상수 시간이 걸리고, in_array()는 모든 값을 훑습니다. 정수처럼 보이는 문자열 키는 변환됩니다. $a['1']과 $a[1]은 같은 요소입니다.

자주 나오는 면접 코딩 과제

라이브로 자주 출제되는 짧은 문제들입니다. 각 함수는 흔한 답 하나입니다. 실행하고, 직접 입력(빈 입력 포함)을 추가하고, 시간 복잡도를 설명할 준비를 하세요. 면접관이 보통 확인하는 것이 그것입니다.

자주 묻는 질문

PHP 개발자 면접은 어떻게 준비하나요?

기본기를 찾아보지 않고 설명하고 코드로 쓸 수 있는지 확인하세요. 비교와 타입, 배열과 배열 함수, OOP(인터페이스, 추상 클래스, 트레이트, static), 예외, 보안(prepared statement, htmlspecialchars, password_hash)입니다. 그다음 프레임워크 하나(Laravel이나 Symfony)와 Composer를 직접 만든 프로젝트를 설명할 수 있을 만큼 잘 아세요.

면접을 위해 어느 PHP 버전을 알아야 하나요?

PHP 8입니다. 면접관은 8.0에서 8.3 사이에 추가된 기능을 알기를 기대합니다. 이름 있는 인수, match, nullsafe 연산자 ?->, 유니언 타입, 생성자 속성 승격, enum, readonly 속성, 일급 callable 문법입니다. PHP 7의 동작은 0 == "a"처럼 바뀐 곳에서만 언급하세요.

신입에게는 어떤 PHP 질문을 하나요?

주로 언어 기초입니다. ==와 ===, echo와 print, 작은따옴표와 큰따옴표, isset과 empty, include와 require, GET과 POST, 세션과 쿠키, 뒤집기, 필터링, 값 세기 같은 간단한 배열 과제입니다. 짧은 코딩 문제가 최소 하나는 나온다고 예상하세요.

경력 개발자에게는 어떤 PHP 질문을 하나요?

설계와 내부 동작입니다. 인터페이스와 추상 클래스, 트레이트, 늦은 정적 바인딩, 참조, 제너레이터와 메모리, 예외와 에러 처리, SQL 인젝션과 트랜잭션, 캐싱, Composer 오토로딩, 기능을 어떻게 구조화하고 테스트할지입니다. 답에는 정의가 아니라 트레이드오프가 함께 와야 합니다.

Coddy 프로그래밍 언어 일러스트

Coddy로 코딩 배우기

시작하기