Devin.KR

PHP · 기본

웹으로 시작하는 PHP

조건과 반복 - match 식까지

if·switch·match, for·foreach·while, 대체 문법(템플릿 안)

개발자KR · 원고 갱신

이 장에서 배우는 것

프로그램은 위에서 아래로 한 줄씩 실행되는 것이 기본이다. 하지만 빵집 주문 사이트는 수량에 따라 할인율이 달라지고, 주문 상태에 따라 안내 문구가 달라지고, 메뉴 목록의 길이도 그날그날 다르다. 이런 일을 하려면 실행 흐름을 갈라 주는 구조(분기)와 같은 일을 여러 번 되풀이하는 구조(반복)가 필요하다. 이 장에서는 두 구조를 PHP 문법으로 쓰는 방법과, HTML 템플릿 안에서 쓰기 편한 대체 문법(alternative syntax)까지 다룬다.

앞 장에서 == 가 값을 바꿔서 비교한다는 점을 조심하라고 했다. 이 장의 switch 는 바로 그 느슨한 비교를 쓰고 match 는 엄격한 비교를 쓴다. 둘의 차이를 실제 코드로 확인한다.

  • if · elseif · else 로 조건에 따라 실행할 코드를 고른다.
  • switch 와 match 의 비교 방식과 결과 처리 방식이 어떻게 다른지 설명하고, 상황에 맞게 고른다.
  • for · foreach · while · do-while 을 목적에 맞게 쓰고, break 와 continue 로 흐름을 조절한다.
  • 템플릿 파일 안에서 if: · foreach: 같은 대체 문법으로 HTML 을 반복 출력한다.

문제 상황

동네 빵집 사장님이 온라인 예약 주문 사이트를 열려고 한다. 지금까지 만든 것은 가격과 수량을 곱해 합계를 내는 계산뿐이다. 그런데 사장님이 요구사항을 하나씩 더 알려 준다.

  • 5개 이상 주문하면 5%, 10개 이상이면 10%, 20개 이상이면 15% 를 깎아 준다.
  • 주문 상태는 received, paid, baked, picked 네 가지이고, 손님에게는 한국어 문구로 보여 준다. 알 수 없는 상태 값이 들어오면 "확인 필요" 로 표시한다.
  • 월요일은 쉬고, 주말은 오후 2시까지만 주문을 받는다.
  • 하루에 만들 수 있는 빵은 12개다. 접수한 수량이 한도를 넘으면 더 받지 않는다. 수량이 0 이하로 잘못 들어온 요청은 건너뛴다.
  • 메뉴 페이지는 오늘 준비된 빵을 목록으로 보여 주고, 준비된 빵이 없으면 안내 문구를 보여 준다.

이 요구사항은 모두 "조건에 따라 다르게" 또는 "여러 번 되풀이" 중 하나다. 이 장에서 이 다섯 가지를 한 프로그램으로 구현한다.

분기: if, switch, match

if · elseif · else

가장 기본적인 분기는 if 다. 소괄호 안의 조건식이 참(true)이면 중괄호 블록(block, 중괄호로 묶은 코드 덩어리)을 실행한다. 조건이 여러 개면 elseif 를 잇고, 어느 것도 아닐 때를 위해 else 를 둘 수 있다.

if ($quantity >= 20) {
    $rate = 15;
} elseif ($quantity >= 10) {
    $rate = 10;
} elseif ($quantity >= 5) {
    $rate = 5;
} else {
    $rate = 0;
}

조건은 위에서 아래로 차례로 검사하고, 처음 참인 갈래를 실행한 뒤에는 나머지를 검사하지 않는다. 그래서 큰 값부터 검사하는 순서가 중요하다. 수량이 25개일 때 >= 5 를 먼저 두면 15% 가 아니라 5% 가 적용된다.

if 와 elseif 는 위에서부터 차례로 검사하다가 처음 참인 조건에서 멈춘다

조건식이 참인지 거짓인지는 앞 장에서 본 규칙을 따른다. 0, 빈 문자열, "0", 빈 배열, null 은 거짓으로 취급된다. 값이 "비어 있는가" 를 묻고 싶은지 "정확히 이 값인가" 를 묻고 싶은지 구분하고, 후자라면 === 로 비교하는 편이 안전하다.

switch

switch 는 하나의 값을 여러 case 와 차례로 비교해 맞는 곳부터 실행한다. 비교에는 == 가 쓰인다. 맞는 case 를 찾으면 break 나 return 을 만날 때까지 아래 case 의 코드까지 이어서 실행한다. 이 성질을 폴스루(fall-through)라고 한다. 아래처럼 의도적으로 여러 case 를 하나로 묶을 때는 편리하다.

switch ($day) {
    case 6:
    case 7:
        return '주말은 오후 2시까지 받는다';
    default:
        return '평일은 오후 6시까지 받는다';
}

반대로 break 를 빼먹으면 의도하지 않은 코드까지 실행된다. 이 문제는 뒤의 "자주 틀리는 것" 에서 다시 본다.

match

match 는 PHP 8.0 에서 들어온 식(expression)이다. 식은 값을 만들어 내는 코드 조각이라, return 이나 변수 대입의 오른쪽에 바로 쓸 수 있다. 각 갈래는 조건값 => 결과값 형태이고, 쉼표로 여러 조건값을 한 갈래에 묶을 수 있다.

$label = match ($status) {
    'received', 'paid' => '준비 중',
    'baked' => '픽업 가능',
    'picked' => '완료',
    default => '확인 필요',
};

match 는 === 로 비교하므로 타입까지 같아야 맞는다. 폴스루가 없어서 break 도 필요 없다. 또 어느 갈래에도 맞지 않고 default 도 없으면 UnhandledMatchError 예외가 발생한다. 처리하지 못한 값을 조용히 넘기지 않고 바로 드러내는 성질이다.

범위를 검사하고 싶을 때는 match (true) 를 쓰는 방법이 있다. 각 갈래의 조건식이 true 와 엄격하게 같은지를 위에서부터 검사하므로, 조건이 true 를 돌려주는 첫 갈래가 선택된다.

$size = match (true) {
    $quantity >= 20 => '대량',
    $quantity >= 5 => '단체',
    default => '일반',
};

switch 와 match 는 무엇이 다른가

switch 와 match 는 비교 방식, 결과 처리, 예외 처리에서 갈린다
항목switchmatch
종류문(statement)식(expression), 값을 돌려준다
비교== (느슨한 비교)=== (엄격한 비교)
다음 갈래로 이어짐있다, break 로 끊는다없다
맞는 갈래가 없을 때아무 일도 없이 지나간다UnhandledMatchError

값을 골라서 돌려주는 일이면 match 가 짧고 안전하다. 갈래마다 여러 문장을 실행해야 하거나 폴스루가 정말 필요할 때만 switch 를 쓴다. 느슨한 비교가 어떤 결과를 내는지는 다음 코드로 확인할 수 있다.

$code = '1e1';   // 숫자 형태의 문자열, 값은 10

switch ($code) {
    case '10':
        echo 'switch: 10 번 갈래';   // 실행된다
        break;
}

echo match ($code) {
    '10' => 'match: 10 번 갈래',
    default => 'match: 그 밖의 값',   // 이쪽이 선택된다
};

'1e1' 과 '10' 은 둘 다 숫자로 읽을 수 있는 문자열이라 == 는 두 값을 숫자 10 으로 보고 같다고 판단한다. 상태 코드나 주문 번호처럼 글자 그대로 맞아야 하는 값에는 이런 비교가 위험하다.

반복: for, foreach, while

반복문 고르기

반복문(loop)은 같은 코드 블록을 조건이 유지되는 동안 되풀이한다. 무엇을 기준으로 반복하느냐에 따라 고른다.

반복 횟수를 아는지, 목록을 훑는지에 따라 반복문을 고른다
문법쓰는 때조건을 검사하는 시점
for횟수나 범위가 정해져 있다본문 실행 전
foreach목록의 원소를 처음부터 끝까지 훑는다원소가 남아 있는 동안
while몇 번인지 모르고 조건이 참인 동안 계속한다본문 실행 전
do-while일단 한 번은 실행해야 한다본문 실행 후

for 는 소괄호 안에 초기화, 조건, 갱신을 세미콜론으로 나눠 적는다. 아래는 1 에서 시작해 3 씩 늘리며 7 이하일 때까지 반복한다.

for ($day = 1; $day <= 7; $day += 3) {
    echo $day, "\n";   // 1, 4, 7
}

foreach 는 목록에서 원소를 하나씩 꺼내 변수에 담는다. 목록을 만드는 [1, 5, 10] 같은 배열(array)은 다음 장에서 자세히 다루므로, 여기서는 "값을 쉼표로 늘어놓은 목록" 정도로 이해하면 된다. $index => $name 처럼 쓰면 원소의 자리 번호도 함께 받는다. 자리 번호는 0 부터 시작한다.

foreach ([1, 5, 10, 20] as $quantity) {
    echo $quantity, "\n";
}

while 은 조건이 참인 동안 본문을 반복한다. 본문 안에서 조건에 쓰이는 값을 바꾸지 않으면 끝나지 않는 반복이 된다.

while ($stock >= 4) {
    $stock -= 4;
}

do-while 은 본문을 먼저 실행하고 조건을 나중에 검사한다. 조건이 처음부터 거짓이어도 본문이 한 번은 실행된다.

break 와 continue

break 는 가장 안쪽 반복을 즉시 끝내고, continue 는 이번 회차의 남은 본문을 건너뛰고 다음 회차로 넘어간다. 접수 한도를 넘으면 그만 받고(break), 잘못된 수량은 건너뛰는(continue) 요구사항에 쓴다.

continue 는 다음 회차로 돌아가고 break 는 조건 검사 없이 반복을 빠져나간다

템플릿 안의 대체 문법

PHP 파일은 <?php 와 ?> 사이만 PHP 코드로 실행하고, 그 밖의 글자는 그대로 출력한다. 이 덕분에 HTML 사이사이에 PHP 를 끼워 넣는 템플릿(template, 출력 모양을 적어 둔 파일)을 만들 수 있다. 그런데 중괄호 { 와 } 를 HTML 사이에 흩어 두면 어디서 닫히는지 알아보기 어렵다. 그래서 PHP 는 중괄호 대신 콜론과 end... 키워드를 쓰는 대체 문법을 제공한다.

대체 문법은 여는 중괄호를 콜론으로, 닫는 중괄호를 end 키워드로 바꾼 것이다
기본 문법대체 문법닫는 키워드
if (...) { }if (...): endif;
foreach (...) { }foreach (...):endforeach;
for (...) { }for (...):endfor;
while (...) { }while (...):endwhile;

값을 바로 출력할 때는 <?= 값 ?> 라는 짧은 표기를 쓴다. <?php echo 값; ?> 와 같은 뜻이다. 사용자가 입력한 글자나 외부에서 온 글자를 HTML 에 넣을 때는 htmlspecialchars() 로 <, >, &, 따옴표를 안전한 표기로 바꿔 준다. 이 내용은 요청과 응답을 다루는 장에서 본격적으로 다룬다. 여기서는 습관으로 미리 익혀 둔다.

PHP 는 ?> 바로 뒤에 오는 줄바꿈 한 개를 출력하지 않고 삼킨다. 그래서 <?php foreach (...): ?> 처럼 줄 끝이 ?> 인 제어 줄은 빈 줄을 남기지 않는다. 반면 <li>...</li> 로 끝나는 줄은 줄바꿈이 그대로 나간다. 이 규칙을 알고 있으면 출력 모양을 정확히 예측할 수 있다.

이 장의 예제는 CLI 에서 확인하도록 템플릿 파일을 require 로 불러온다. require 는 다른 PHP 파일을 그 자리에서 실행하는 문법이고, 불러온 파일은 불러온 쪽의 변수를 그대로 볼 수 있다. 브라우저로 결과를 보는 방법은 요청과 응답을 다루는 장에서 php -S 로 내장 웹 서버를 띄우며 설명한다. 조건과 반복 문법 자체는 CLI 든 웹이든 같다.

참고 문서: match, 대체 문법.

완성 코드

두 파일을 같은 디렉터리에 둔다. main.php 가 계산과 흐름을 맡고, menu.php 가 메뉴 출력 모양을 맡는다.

main.php

<?php

declare(strict_types=1);

function discountRate(int $quantity): int
{
    if ($quantity >= 20) {
        return 15;
    } elseif ($quantity >= 10) {
        return 10;
    } elseif ($quantity >= 5) {
        return 5;
    }

    return 0;
}

function orderStatusLabel(string $status): string
{
    return match ($status) {
        'received', 'paid' => '준비 중',
        'baked' => '픽업 가능',
        'picked' => '완료',
        default => '확인 필요',
    };
}

function weekdayNotice(int $day): string
{
    switch ($day) {
        case 1:
            return '월요일은 휴무다';
        case 6:
        case 7:
            return '주말은 오후 2시까지 받는다';
        default:
            return '평일은 오후 6시까지 받는다';
    }
}

$unitPrice = 3500;

echo "== 수량별 할인 ==\n";
foreach ([1, 5, 10, 20] as $quantity) {
    $rate = discountRate($quantity);
    $total = intdiv($unitPrice * $quantity * (100 - $rate), 100);
    echo "{$quantity}개: {$rate}% 할인, {$total}원\n";
}

echo "== 주문 상태 ==\n";
foreach (['received', 'baked', 'picked', 'shipped'] as $status) {
    echo $status, ' -> ', orderStatusLabel($status), "\n";
}

echo "== 요일별 안내 ==\n";
for ($day = 1; $day <= 7; $day += 3) {
    echo $day, ': ', weekdayNotice($day), "\n";
}

echo "== 접수 ==\n";
$capacity = 12;
$accepted = 0;
foreach ([4, 0, 5, -1, 6, 2] as $quantity) {
    if ($quantity <= 0) {
        echo "수량 {$quantity}: 건너뜀\n";
        continue;
    }
    if ($accepted + $quantity > $capacity) {
        echo "수량 {$quantity}: 한도 초과, 접수 종료\n";
        break;
    }
    $accepted += $quantity;
    echo "수량 {$quantity}: 접수, 누계 {$accepted}개\n";
}
echo "접수 합계: {$accepted}개\n";

echo "== 재고 소진 ==\n";
$stock = 10;
$orderNo = 0;
while ($stock >= 4) {
    $stock -= 4;
    $orderNo++;
    echo "주문 {$orderNo}: 4개 판매, 남은 재고 {$stock}개\n";
}
echo "재고 {$stock}개로는 다음 주문을 받을 수 없다\n";

echo "== 번호표 호출 ==\n";
$waiting = 0;
$called = 0;
do {
    $called++;
    echo "번호표 {$called} 호출\n";
} while ($called < $waiting);

echo "== 메뉴 템플릿 ==\n";
$menuTitle = '오늘의 빵';
$breadNames = ['식빵', '소보로', '단팥빵'];
require __DIR__ . '/menu.php';

$menuTitle = '내일의 빵';
$breadNames = [];
require __DIR__ . '/menu.php';

menu.php

<?php declare(strict_types=1); ?>
<h2><?= htmlspecialchars($menuTitle) ?></h2>
<?php if (count($breadNames) === 0): ?>
<p>오늘은 준비된 빵이 없다</p>
<?php else: ?>
<ul>
<?php foreach ($breadNames as $index => $name): ?>
  <li><?= $index + 1 ?>. <?= htmlspecialchars($name) ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>

줄별 해설

main.php: 함수 세 개

  • discountRate(int $quantity): int: 수량을 받아 할인율(퍼센트 정수)을 돌려준다. 큰 기준부터 if, elseif 로 검사하므로 20개 이상은 첫 갈래에서 끝난다. 어느 조건에도 맞지 않으면 블록을 지나 마지막 return 0; 이 실행된다. else 없이 뒤에 return 을 두는 방식이다.
  • orderStatusLabel: match 식 전체가 return 의 값이 된다. 'received', 'paid' 는 한 갈래에 묶였다. default 가 있어서 'shipped' 같은 모르는 값도 예외 없이 "확인 필요" 가 된다.
  • weekdayNotice: switch 의 case 6: 에는 실행문이 없어서 아래 case 7: 로 이어진다. 6 과 7 이 같은 문구를 쓰게 하는 의도적인 폴스루다. 모든 갈래가 return 하므로 break 는 필요 없다.

main.php: 실행 흐름

  • $unitPrice = 3500;: 빵 한 개의 가격이다.
  • 첫 foreach: 수량 목록에서 하나씩 꺼내 $quantity 에 담는다. 합계는 단가 x 수량 x (100 - 할인율) 을 100 으로 나눈 값이다. 소수점 계산을 피하려고 intdiv() 로 정수 나눗셈을 했다. 문자열 안의 {$변수} 는 값으로 치환된다. 한글이 바로 뒤에 붙어도 변수 이름의 끝이 분명하도록 중괄호를 썼다.
  • 상태 foreach: echo 에 쉼표로 여러 값을 이어 적으면 차례로 출력한다.
  • for ($day = 1; $day <= 7; $day += 3): $day 는 1, 4, 7 이 된다. 4 는 default 갈래로 가서 평일 문구가 나온다.
  • 접수 foreach: 0 과 -1 은 첫 if 에서 continue 로 건너뛴다. 4 와 5 는 접수되어 누계가 9 가 된다. 6 은 9 + 6 > 12 라서 break 로 반복 자체를 끝낸다. 뒤에 있는 2 는 검사조차 하지 않는다.
  • while ($stock >= 4): 재고 10 에서 4 를 두 번 빼면 2 가 남고, 조건이 거짓이 되어 끝난다. 본문에서 $stock 을 줄이기 때문에 반드시 끝난다.
  • do-while: 기다리는 사람이 0 명이어도 본문이 한 번 실행되어 번호표 1 을 호출한다. 그다음 1 < 0 이 거짓이라 끝난다. 이런 성질 때문에 "일단 한 번 하고 판단" 하는 경우에만 쓴다.
  • 마지막 두 require: 같은 템플릿을 변수 값만 바꿔 두 번 실행한다.

menu.php

  • 첫 줄: 템플릿 파일에도 declare(strict_types=1); 를 둘 수 있다. 첫 문장이어야 하므로 파일 맨 앞에 쓴다. 뒤의 ?> 와 줄바꿈은 출력되지 않는다.
  • <h2><?= htmlspecialchars($menuTitle) ?></h2>: 제목을 이스케이프해서 출력한다.
  • <?php if (...): ?> ... <?php else: ?> ... <?php endif; ?>: 목록이 비었을 때와 아닐 때를 나눈다. 제어 줄은 ?> 로 끝나서 출력에 빈 줄을 남기지 않는다.
  • foreach (... as $index => $name):: 자리 번호와 이름을 함께 받는다. 자리 번호는 0 부터라서 $index + 1 로 사람이 읽는 번호를 만든다. <li> 줄은 줄바꿈까지 그대로 출력된다.

실행 결과

두 파일이 있는 디렉터리에서 실행한다.

$ php main.php
== 수량별 할인 ==
1개: 0% 할인, 3500원
5개: 5% 할인, 16625원
10개: 10% 할인, 31500원
20개: 15% 할인, 59500원
== 주문 상태 ==
received -> 준비 중
baked -> 픽업 가능
picked -> 완료
shipped -> 확인 필요
== 요일별 안내 ==
1: 월요일은 휴무다
4: 평일은 오후 6시까지 받는다
7: 주말은 오후 2시까지 받는다
== 접수 ==
수량 4: 접수, 누계 4개
수량 0: 건너뜀
수량 5: 접수, 누계 9개
수량 -1: 건너뜀
수량 6: 한도 초과, 접수 종료
접수 합계: 9개
== 재고 소진 ==
주문 1: 4개 판매, 남은 재고 6개
주문 2: 4개 판매, 남은 재고 2개
재고 2개로는 다음 주문을 받을 수 없다
== 번호표 호출 ==
번호표 1 호출
== 메뉴 템플릿 ==
<h2>오늘의 빵</h2>
<ul>
  <li>1. 식빵</li>
  <li>2. 소보로</li>
  <li>3. 단팥빵</li>
</ul>
<h2>내일의 빵</h2>
<p>오늘은 준비된 빵이 없다</p>

실무에서 자주 틀리는 것

1. switch 에서 break 를 빼먹는다

틀린 코드는 received 를 넣어도 다음 case 로 흘러가서 마지막 대입이 덮어쓴다.

switch ($status) {
    case 'received':
        $label = '준비 중';
    case 'baked':
        $label = '픽업 가능';
        break;
}
// $status 가 'received' 여도 $label 은 '픽업 가능'

고친 코드는 값을 고르는 일이므로 match 로 바꾼다. 폴스루 자체가 없다.

$label = match ($status) {
    'received' => '준비 중',
    'baked' => '픽업 가능',
    default => '확인 필요',
};

2. match 에 default 를 두지 않는다

틀린 코드는 정해 둔 값만 들어온다고 믿고 default 를 뺐다. 외부에서 온 값이 목록에 없으면 UnhandledMatchError 로 프로그램이 멈춘다.

$label = match ($status) {
    'received' => '준비 중',
    'baked' => '픽업 가능',
};
// $status 가 'shipped' 이면 예외 발생

고친 코드는 처리할 수 없는 값의 응답을 default 로 정한다. 값이 정말 그 목록 안에만 있어야 하는 곳이라면 일부러 default 를 빼서 예외로 알아차리는 방법도 있다. 다만 사용자 입력이 닿는 곳에서는 default 를 두는 쪽이 낫다.

$label = match ($status) {
    'received' => '준비 중',
    'baked' => '픽업 가능',
    default => '확인 필요',
};

3. if 조건에서 = 를 쓴다

= 는 대입이다. 조건 안에서 대입하면 대입한 값이 그대로 조건의 결과가 되어서, 5 는 참으로 취급되므로 항상 블록이 실행된다. 게다가 $quantity 값이 덮어써진다.

if ($quantity = 5) {
    echo '5개 주문';   // 수량이 얼마든 실행된다
}

고친 코드는 비교 연산자를 쓴다. 엄격한 비교인 === 가 앞 장에서 배운 안전한 기본값이다.

if ($quantity === 5) {
    echo '5개 주문';
}

4. 대체 문법에서 else if 를 두 단어로 쓴다

중괄호 문법에서는 else if 도 동작하지만, 콜론을 쓰는 대체 문법에서는 문법 오류(parse error)가 난다.

<?php if ($count > 0): ?>
  <p>주문이 있다</p>
<?php else if ($count < 0): ?>
  <p>수량 오류</p>
<?php endif; ?>

고친 코드는 한 단어인 elseif 를 쓴다. 습관적으로 항상 elseif 로 쓰면 두 문법 모두에서 안전하다.

<?php if ($count > 0): ?>
  <p>주문이 있다</p>
<?php elseif ($count < 0): ?>
  <p>수량 오류</p>
<?php endif; ?>

한눈에 보기

이 장에서 다룬 제어 구조와 쓰임새
구조한 줄 요약주의할 점
if / elseif / else조건에 따라 코드 블록을 고른다위에서부터 검사, 조건 순서가 결과를 바꾼다
switch값 하나를 여러 case 와 == 로 비교한다느슨한 비교, break 를 빼면 아래로 흐른다
match값을 === 로 비교해 결과 값을 돌려주는 식맞는 갈래가 없으면 예외, default 로 대비
for횟수나 범위가 정해진 반복조건과 갱신을 헷갈리면 한 번 더 돌거나 덜 돈다
foreach목록의 원소를 차례로 훑는다자리 번호는 0 부터 시작한다
while / do-while조건이 참인 동안 반복한다조건에 쓰이는 값을 본문에서 바꿔야 끝난다
break / continue반복을 끝내거나 이번 회차를 건너뛴다가장 안쪽 반복에만 적용된다
대체 문법콜론과 end... 로 HTML 사이에서 읽기 쉽게 쓴다elseif 는 한 단어로 쓴다

연습 문제

  1. 시각(0 에서 23 사이의 정수)을 받아 10시 전이면 "오픈 전", 10시 이상 18시 미만이면 "영업 중", 그 밖에는 "마감" 을 돌려주는 함수 shopState(int $hour): string 을 match (true) 로 작성하라.
  2. 1 부터 10 까지 반복하면서 3 의 배수는 건너뛰고 나머지 수를 모두 더한 합계를 출력하는 코드를 for 와 continue 로 작성하라.
  3. 식빵 반죽이 1000g 있고 빵 한 개에 120g 이 든다. while 로 만들 수 있는 빵의 개수와 남는 반죽의 양을 구하라. 나눗셈 연산자는 쓰지 않는다.
  4. 템플릿 파일에서 for 의 대체 문법으로 1 부터 3 까지의 번호를 <ol> 목록의 항목으로 출력하는 코드를 작성하라. 항목 내용은 "예약 1번" 형태로 한다.

정답과 해설

1번

function shopState(int $hour): string
{
    return match (true) {
        $hour < 10 => '오픈 전',
        $hour < 18 => '영업 중',
        default => '마감',
    };
}

match (true) 는 위에서부터 조건식의 결과가 true 인 첫 갈래를 고른다. 두 번째 갈래에 도달했다는 것은 이미 10시 이상이라는 뜻이므로 $hour >= 10 을 다시 쓰지 않아도 된다. 예를 들어 9 는 "오픈 전", 14 는 "영업 중", 20 은 "마감" 이다.

2번

$sum = 0;
for ($i = 1; $i <= 10; $i++) {
    if ($i % 3 === 0) {
        continue;
    }
    $sum += $i;
}
echo $sum, "\n";

% 는 나머지 연산자다. 3 의 배수(3, 6, 9)는 continue 로 건너뛰므로 1 + 2 + 4 + 5 + 7 + 8 + 10 이 더해져 37 이 출력된다.

3번

$dough = 1000;
$count = 0;
while ($dough >= 120) {
    $dough -= 120;
    $count++;
}
echo "{$count}개, 남은 반죽 {$dough}g\n";

반죽이 120g 이상인 동안 120 을 빼고 개수를 센다. 8번 반복하면 960g 을 쓰고 40g 이 남아서 조건이 거짓이 된다. 출력은 8개, 남은 반죽 40g 이다. 조건이 > 120 이면 반죽이 정확히 120g 남았을 때 하나를 만들지 못하므로, 경계값에서 >= 와 > 를 구분해야 한다.

4번

<ol>
<?php for ($n = 1; $n <= 3; $n++): ?>
  <li>예약 <?= $n ?>번</li>
<?php endfor; ?>
</ol>

대체 문법에서는 for (...): 로 열고 endfor; 로 닫는다. 제어 줄이 ?> 로 끝나므로 빈 줄 없이 <li> 세 줄이 출력된다.

오탈자·오류 제보 비공개로 접수되어 원고 수정에 반영됩니다

이메일 등 개인정보는 받지 않습니다. 답변이 필요한 질문은 아래 댓글을 이용해 주세요.

READER FEEDBACK

질문·의견

내용에 관한 질문이나 더 나은 설명을 위한 의견을 남겨 주세요. 오탈자는 위의 제보 양식이 더 빨리 반영됩니다. 이 댓글은 원래 게시글과 같은 자리에 쌓입니다.

댓글 0

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

댓글을 남기려면 로그인이 필요합니다.