์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿš€ PHP ๋„ค์ž„์ŠคํŽ˜์ด์Šค์™€ ์˜คํ† ๋กœ๋”ฉ, PSR-4 ํ‘œ์ค€์œผ๋กœ ์ฝ”๋“œ ๊ตฌ์กฐ๋ฅผ ์™„๋ฒฝํ•˜๊ฒŒ ์ •๋ฆฌํ•˜๋Š” ๋ฒ•

๐Ÿš€ PHP ๋„ค์ž„์ŠคํŽ˜์ด์Šค์™€ ์˜คํ† ๋กœ๋”ฉ, PSR-4 ํ‘œ์ค€์œผ๋กœ ์ฝ”๋“œ ๊ตฌ์กฐ๋ฅผ ์™„๋ฒฝํ•˜๊ฒŒ ์ •๋ฆฌํ•˜๋Š” ๋ฒ•

๋ณต์žกํ•œ PHP ํ”„๋กœ์ ํŠธ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ๊ด€๋ฆฌํ•˜๋Š” ํ˜„๋Œ€์ ์ธ ๋ฐฉ๋ฒ•

๐Ÿ’ฌ ์•ผ, ๋„ˆ PHP๋กœ ํ”„๋กœ์ ํŠธ ๋งŒ๋“ค๋‹ค๊ฐ€ ํŒŒ์ผ์ด ์ˆ˜์‹ญ ๊ฐœ, ์ˆ˜๋ฐฑ ๊ฐœ๋กœ ๋Š˜์–ด๋‚˜๋ฉด์„œ "์ด๊ฑฐ ์–ด๋”” ์žˆ๋”๋ผ?" ํ•˜๋ฉด์„œ ํ—ค๋งจ ์  ์žˆ์ง€? ๐Ÿ˜…
ํด๋ž˜์Šค ์ด๋ฆ„์ด ๊ฒน์ณ์„œ ์—๋Ÿฌ ๋‚˜๊ณ , require ๋ฌธ์žฅ์ด ํŒŒ์ผ๋งˆ๋‹ค ์ˆ˜์‹ญ ์ค„์”ฉ ๋Š˜์–ด๋‚˜๊ณ ... ์ง„์งœ ๋จธ๋ฆฌ ์•„ํ”„์ง€?

์˜ค๋Š˜์€ ๊ทธ๋Ÿฐ ๊ณ ๋ฏผ์„ ์‹น ๋‚ ๋ ค์ค„ ๋„ค์ž„์ŠคํŽ˜์ด์Šค(Namespace)์™€ ์˜คํ† ๋กœ๋”ฉ(Autoloading), ๊ทธ๋ฆฌ๊ณ  PSR-4 ํ‘œ์ค€์— ๋Œ€ํ•ด ์นœ๊ตฌ์ฒ˜๋Ÿผ ํŽธํ•˜๊ฒŒ ์ด์•ผ๊ธฐํ•ด๋ณผ๊ฒŒ! ๐ŸŽฏ

์ด ๊ธ€ ํ•˜๋‚˜๋ฉด PHP ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐํ™”์˜ A to Z๋ฅผ ์™„๋ฒฝํ•˜๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์„ ๊ฑฐ์•ผ. ์žฌ๋Šฅ๋„ท์—์„œ PHP ๊ฐœ๋ฐœ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•˜๊ฑฐ๋‚˜ ๋ฐฐ์šฐ๋ ค๋Š” ์‚ฌ๋žŒ๋“ค์—๊ฒŒ๋„ ๋”ฑ ํ•„์š”ํ•œ ๋‚ด์šฉ์ด๋‹ˆ๊นŒ ๋๊นŒ์ง€ ์ง‘์ค‘! ๐Ÿ”ฅ

์˜›๋‚  ๋ฐฉ์‹ require ์ง€์˜ฅ ํด๋ž˜์Šค ์ด๋ฆ„ ์ถฉ๋Œ ๊ด€๋ฆฌ ๋ถˆ๊ฐ€๋Šฅ ํ˜„๋Œ€ ๋ฐฉ์‹ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์˜คํ† ๋กœ๋”ฉ PSR-4 ํ‘œ์ค€ ์ง„ํ™”! ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์ด๋ฆ„ ์ถฉ๋Œ ํ•ด๊ฒฐ ๋…ผ๋ฆฌ์  ๊ทธ๋ฃนํ™” ์˜คํ† ๋กœ๋”ฉ ์ž๋™ ํŒŒ์ผ ๋กœ๋“œ require ์ œ๊ฑฐ PSR-4 ํ‘œ์ค€ ๊ทœ์น™ ์ผ๊ด€๋œ ๊ตฌ์กฐ ์™„๋ฒฝํ•œ ์กฐํ•ฉ์œผ๋กœ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐํ™”!

๐Ÿค” ์™œ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๊ฐ€ ํ•„์š”ํ• ๊นŒ?

์ž, ๋จผ์ € ๋„ค์ž„์ŠคํŽ˜์ด์Šค๊ฐ€ ์™œ ํ•„์š”ํ•œ์ง€๋ถ€ํ„ฐ ์ดํ•ดํ•ด๋ณด์ž.
PHP ์ดˆ์ฐฝ๊ธฐ์—๋Š” ํ”„๋กœ์ ํŠธ ๊ทœ๋ชจ๊ฐ€ ์ž‘์•˜์–ด. ํŒŒ์ผ ๋ช‡ ๊ฐœ, ํด๋ž˜์Šค ๋ช‡ ๊ฐœ๋ฉด ์ถฉ๋ถ„ํ–ˆ์ง€.
๊ทธ๋Ÿฐ๋ฐ ํ”„๋กœ์ ํŠธ๊ฐ€ ์ปค์ง€๋ฉด์„œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๊ธฐ ์‹œ์ž‘ํ–ˆ์–ด. ๐Ÿ˜ฐ

โš ๏ธ ์˜›๋‚  ๋ฐฉ์‹์˜ ๋ฌธ์ œ์ ๋“ค 1. ํด๋ž˜์Šค ์ด๋ฆ„ ์ถฉ๋Œ
๋„ˆ๊ฐ€ User ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์—ˆ๋Š”๋ฐ, ์‚ฌ์šฉํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์—๋„ User ํด๋ž˜์Šค๊ฐ€ ์žˆ์œผ๋ฉด? ๐Ÿ’ฅ ์ถฉ๋Œ!

2. ๊ธด ํด๋ž˜์Šค ์ด๋ฆ„
์ถฉ๋Œ์„ ํ”ผํ•˜๋ ค๊ณ  MyProject_Database_MySQL_Connection ์ด๋Ÿฐ ์‹์œผ๋กœ ์ด๋ฆ„์„ ๊ธธ๊ฒŒ ๋งŒ๋“ค์–ด์•ผ ํ–ˆ์–ด.

3. ๊ด€๋ฆฌ์˜ ์–ด๋ ค์›€
์–ด๋–ค ํด๋ž˜์Šค๊ฐ€ ์–ด๋””์— ์†ํ•˜๋Š”์ง€, ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€ ํŒŒ์•…ํ•˜๊ธฐ ํž˜๋“ค์—ˆ์ง€.

์ด๋Ÿฐ ๋ฌธ์ œ๋“ค์„ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด PHP 5.3๋ถ€ํ„ฐ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๊ฐ€ ๋„์ž…๋์–ด! ๐ŸŽ‰
๋„ค์ž„์ŠคํŽ˜์ด์Šค๋Š” ์‰ฝ๊ฒŒ ๋งํ•ด์„œ "ํด๋ž˜์Šค๋“ค์˜ ์ฃผ์†Œ"๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ผ.

ํ˜„์‹ค ์„ธ๊ณ„์—์„œ๋„ "๊น€์ฒ ์ˆ˜"๋ผ๋Š” ์ด๋ฆ„์„ ๊ฐ€์ง„ ์‚ฌ๋žŒ์ด ์—ฌ๋Ÿฌ ๋ช… ์žˆ์„ ์ˆ˜ ์žˆ์ž–์•„?
๊ทธ๋Ÿฐ๋ฐ "์„œ์šธ์‹œ ๊ฐ•๋‚จ๊ตฌ์— ์‚ฌ๋Š” ๊น€์ฒ ์ˆ˜"์™€ "๋ถ€์‚ฐ์‹œ ํ•ด์šด๋Œ€๊ตฌ์— ์‚ฌ๋Š” ๊น€์ฒ ์ˆ˜"๋Š” ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ์ง€?
๋„ค์ž„์ŠคํŽ˜์ด์Šค๊ฐ€ ๋ฐ”๋กœ ์ด๋Ÿฐ ์—ญํ• ์„ ํ•ด! ๐Ÿ“

๐ŸŽฏ ๋„ค์ž„์ŠคํŽ˜์ด์Šค์˜ ํ•ต์‹ฌ ๊ฐœ๋… โ€ข ๋…ผ๋ฆฌ์  ๊ทธ๋ฃนํ™”: ๊ด€๋ จ๋œ ํด๋ž˜์Šค๋“ค์„ ํ•˜๋‚˜์˜ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋กœ ๋ฌถ์–ด์„œ ๊ด€๋ฆฌ
โ€ข ์ด๋ฆ„ ์ถฉ๋Œ ๋ฐฉ์ง€: ๊ฐ™์€ ์ด๋ฆ„์˜ ํด๋ž˜์Šค๋„ ๋‹ค๋ฅธ ๋„ค์ž„์ŠคํŽ˜์ด์Šค์— ์žˆ์œผ๋ฉด ๋ฌธ์ œ์—†์Œ
โ€ข ์ฝ”๋“œ ๊ฐ€๋…์„ฑ: ํด๋ž˜์Šค์˜ ์—ญํ• ๊ณผ ์œ„์น˜๋ฅผ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋งŒ ๋ด๋„ ์•Œ ์ˆ˜ ์žˆ์Œ
โ€ข ํ‘œ์ค€ํ™”: PSR-4 ๊ฐ™์€ ํ‘œ์ค€์„ ๋”ฐ๋ฅด๋ฉด ๋ชจ๋“  ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ฝ”๋“œ ์ž‘์„ฑ

๐Ÿ“š ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๊ธฐ๋ณธ ๋ฌธ๋ฒ•๊ณผ ์‚ฌ์šฉ๋ฒ•

์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์•Œ์•„๋ณด์ž!
๊ฑฑ์ • ๋งˆ, ์ƒ๊ฐ๋ณด๋‹ค ํ›จ์”ฌ ๊ฐ„๋‹จํ•ด. ๐Ÿ˜Š

๐Ÿ”น ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์„ ์–ธํ•˜๊ธฐ

๋„ค์ž„์ŠคํŽ˜์ด์Šค๋Š” PHP ํŒŒ์ผ์˜ ๋งจ ์œ„์— ์„ ์–ธํ•ด์•ผ ํ•ด.

<?php
namespace App\Models;

class User
{
    public function getName()
    {
        return "ํ™๊ธธ๋™";
    }
}

์œ„ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด namespace App\Models;๋ผ๊ณ  ์„ ์–ธํ–ˆ์ง€?
์ด์ œ ์ด User ํด๋ž˜์Šค์˜ ์ •์‹ ์ด๋ฆ„์€ App\Models\User๊ฐ€ ๋˜๋Š” ๊ฑฐ์•ผ.
๋ฐฑ์Šฌ๋ž˜์‹œ(\)๋กœ ๊ณ„์ธต์„ ๊ตฌ๋ถ„ํ•˜๋Š”๋ฐ, ์ด๊ฑด ๋งˆ์น˜ ํด๋” ๊ตฌ์กฐ์ฒ˜๋Ÿผ ์ƒ๊ฐํ•˜๋ฉด ๋ผ! ๐Ÿ“

๐Ÿ’ก ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๋„ค์ด๋ฐ ๊ทœ์น™ โ€ข ์ฒซ ๊ธ€์ž๋Š” ๋Œ€๋ฌธ์ž๋กœ ์‹œ์ž‘ (PascalCase)
โ€ข ๋ฐฑ์Šฌ๋ž˜์‹œ(\)๋กœ ๊ณ„์ธต ๊ตฌ๋ถ„
โ€ข ์ผ๋ฐ˜์ ์œผ๋กœ ํšŒ์‚ฌ๋ช…์ด๋‚˜ ํ”„๋กœ์ ํŠธ๋ช…์œผ๋กœ ์‹œ์ž‘ (์˜ˆ: App, MyCompany)
โ€ข ์˜๋ฏธ ์žˆ๋Š” ์ด๋ฆ„ ์‚ฌ์šฉ (Models, Controllers, Services ๋“ฑ)
๐Ÿ”น ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์‚ฌ์šฉํ•˜๊ธฐ

๋‹ค๋ฅธ ํŒŒ์ผ์—์„œ ๋„ค์ž„์ŠคํŽ˜์ด์Šค์— ์žˆ๋Š” ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ?
ํฌ๊ฒŒ ์„ธ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ์–ด!

๋ฐฉ๋ฒ• 1: ์ „์ฒด ๊ฒฝ๋กœ(Fully Qualified Name) ์‚ฌ์šฉ
<?php
$user = new \App\Models\User();
echo $user->getName();

๋งจ ์•ž์— ๋ฐฑ์Šฌ๋ž˜์‹œ(\)๋ฅผ ๋ถ™์—ฌ์„œ ์ „์ฒด ๊ฒฝ๋กœ๋ฅผ ๋‹ค ์จ์ฃผ๋Š” ๋ฐฉ๋ฒ•์ด์•ผ.
ํ™•์‹คํ•˜์ง€๋งŒ ๋งค๋ฒˆ ์“ฐ๊ธฐ์—” ์ข€ ๊ธธ์ง€? ๐Ÿ˜…

๋ฐฉ๋ฒ• 2: use ํ‚ค์›Œ๋“œ๋กœ ์ž„ํฌํŠธ
<?php
use App\Models\User;

$user = new User();
echo $user->getName();

use ํ‚ค์›Œ๋“œ๋กœ ๋ฏธ๋ฆฌ ์„ ์–ธํ•ด๋‘๋ฉด ์งง์€ ์ด๋ฆ„์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด!
๊ฐ€์žฅ ๋งŽ์ด ์“ฐ๋Š” ๋ฐฉ๋ฒ•์ด๊ณ , ์ฝ”๋“œ๋„ ๊น”๋”ํ•ด์ ธ. โœจ

๋ฐฉ๋ฒ• 3: ๋ณ„์นญ(Alias) ์‚ฌ์šฉ
<?php
use App\Models\User as UserModel;

$user = new UserModel();
echo $user->getName();

as ํ‚ค์›Œ๋“œ๋กœ ๋ณ„์นญ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด.
์ด๋ฆ„์ด ์ถฉ๋Œํ•˜๊ฑฐ๋‚˜ ๋” ๋ช…ํ™•ํ•œ ์ด๋ฆ„์„ ์“ฐ๊ณ  ์‹ถ์„ ๋•Œ ์œ ์šฉํ•ด! ๐Ÿท๏ธ

๐Ÿ”น ์—ฌ๋Ÿฌ ํด๋ž˜์Šค ํ•œ ๋ฒˆ์— ์ž„ํฌํŠธํ•˜๊ธฐ

๊ฐ™์€ ๋„ค์ž„์ŠคํŽ˜์ด์Šค์—์„œ ์—ฌ๋Ÿฌ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด?
PHP 7๋ถ€ํ„ฐ๋Š” ๊ทธ๋ฃน use ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด!

<?php
// ์˜›๋‚  ๋ฐฉ์‹
use App\Models\User;
use App\Models\Post;
use App\Models\Comment;

// ํ˜„๋Œ€ ๋ฐฉ์‹ (๊ทธ๋ฃน use)
use App\Models\{User, Post, Comment};

ํ›จ์”ฌ ๊น”๋”ํ•˜์ง€? ๐Ÿ˜Ž
์ฝ”๋“œ ์ค„ ์ˆ˜๋„ ์ค„๊ณ , ๊ฐ€๋…์„ฑ๋„ ์ข‹์•„์ ธ!

๐ŸŽฏ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๊ณ ๊ธ‰ ํ™œ์šฉ๋ฒ•

๊ธฐ๋ณธ์€ ์ด์ œ ์•Œ์•˜์œผ๋‹ˆ, ์ข€ ๋” ๊นŠ์ด ๋“ค์–ด๊ฐ€๋ณผ๊นŒ?
์‹ค์ „์—์„œ ์œ ์šฉํ•œ ๊ณ ๊ธ‰ ๊ธฐ๋ฒ•๋“ค์„ ์•Œ๋ ค์ค„๊ฒŒ! ๐Ÿš€

๐Ÿ”น ์„œ๋ธŒ ๋„ค์ž„์ŠคํŽ˜์ด์Šค (Sub-namespace)

๋„ค์ž„์ŠคํŽ˜์ด์Šค๋Š” ์—ฌ๋Ÿฌ ๋‹จ๊ณ„๋กœ ์ค‘์ฒฉํ•  ์ˆ˜ ์žˆ์–ด.
ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ๋ฅผ ๋” ์„ธ๋ฐ€ํ•˜๊ฒŒ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์ง€!

<?php
// App/Models/Database/MySQL/Connection.php
namespace App\Models\Database\MySQL;

class Connection
{
    public function connect()
    {
        return "MySQL ์—ฐ๊ฒฐ ์„ฑ๊ณต!";
    }
}

// ์‚ฌ์šฉํ•  ๋•Œ
use App\Models\Database\MySQL\Connection;
$conn = new Connection();

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ด€๋ จ ์ฝ”๋“œ๋ฅผ ๋” ์ฒด๊ณ„์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด.
MySQL, PostgreSQL, MongoDB ๋“ฑ์„ ๊ฐ๊ฐ ๋‹ค๋ฅธ ์„œ๋ธŒ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋กœ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฑฐ์ง€! ๐Ÿ“Š

๐Ÿ”น ์ „์—ญ ๋„ค์ž„์ŠคํŽ˜์ด์Šค์™€ ์ƒ๋Œ€ ์ฐธ์กฐ

๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋‹ค ๋ณด๋ฉด PHP ๋‚ด์žฅ ํด๋ž˜์Šค๋ฅผ ์“ธ ๋•Œ ์ฃผ์˜ํ•ด์•ผ ํ•ด.
์™œ๋ƒํ•˜๋ฉด ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์•ˆ์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ํ˜„์žฌ ๋„ค์ž„์ŠคํŽ˜์ด์Šค์—์„œ ํด๋ž˜์Šค๋ฅผ ์ฐพ๊ธฐ ๋•Œ๋ฌธ์ด์•ผ!

<?php
namespace App\Models;

class User
{
    public function createDate()
    {
        // ์ž˜๋ชป๋œ ๋ฐฉ๋ฒ• - App\Models\DateTime์„ ์ฐพ์œผ๋ ค๊ณ  ํ•จ
        // $date = new DateTime();
        
        // ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ• 1 - ์ „์—ญ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๋ช…์‹œ
        $date = new \DateTime();
        
        // ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ• 2 - use๋กœ ์ž„ํฌํŠธ
        // use DateTime;
        // $date = new DateTime();
        
        return $date;
    }
}
โš ๏ธ ์ฃผ์˜์‚ฌํ•ญ PHP ๋‚ด์žฅ ํด๋ž˜์Šค(DateTime, PDO, Exception ๋“ฑ)๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š”
๋ฐ˜๋“œ์‹œ ์•ž์— ๋ฐฑ์Šฌ๋ž˜์‹œ(\)๋ฅผ ๋ถ™์ด๊ฑฐ๋‚˜ use๋กœ ์ž„ํฌํŠธํ•ด์•ผ ํ•ด!
์•ˆ ๊ทธ๋Ÿฌ๋ฉด ํ˜„์žฌ ๋„ค์ž„์ŠคํŽ˜์ด์Šค์—์„œ ํ•ด๋‹น ํด๋ž˜์Šค๋ฅผ ์ฐพ์œผ๋ ค๊ณ  ํ•ด์„œ ์—๋Ÿฌ๊ฐ€ ๋‚˜!
๐Ÿ”น ๋„ค์ž„์ŠคํŽ˜์ด์Šค์™€ ํ•จ์ˆ˜, ์ƒ์ˆ˜

๋„ค์ž„์ŠคํŽ˜์ด์Šค๋Š” ํด๋ž˜์Šค๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํ•จ์ˆ˜์™€ ์ƒ์ˆ˜์—๋„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์–ด!
๋งŽ์ด ์‚ฌ์šฉํ•˜์ง„ ์•Š์ง€๋งŒ, ์•Œ์•„๋‘๋ฉด ์œ ์šฉํ•œ ๊ธฐ๋Šฅ์ด์•ผ.

<?php
namespace App\Helpers;

// ๋„ค์ž„์ŠคํŽ˜์ด์Šค ํ•จ์ˆ˜
function formatDate($date)
{
    return date('Y-m-d', strtotime($date));
}

// ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์ƒ์ˆ˜
const APP_VERSION = '1.0.0';

// ์‚ฌ์šฉํ•  ๋•Œ
use function App\Helpers\formatDate;
use const App\Helpers\APP_VERSION;

echo formatDate('2024-01-15');
echo APP_VERSION;

ํ•จ์ˆ˜๋Š” use function, ์ƒ์ˆ˜๋Š” use const๋กœ ์ž„ํฌํŠธํ•ด!
ํ—ฌํผ ํ•จ์ˆ˜๋‚˜ ์„ค์ • ์ƒ์ˆ˜๋ฅผ ๊ด€๋ฆฌํ•  ๋•Œ ๊น”๋”ํ•˜๊ฒŒ ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด. ๐Ÿงน

๐Ÿค– ์˜คํ† ๋กœ๋”ฉ์˜ ๋งˆ๋ฒ•

์ž, ์ด์ œ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋Š” ์™„๋ฒฝํ•˜๊ฒŒ ์ดํ•ดํ–ˆ์ง€?
๊ทธ๋Ÿฐ๋ฐ ์•„์ง ํ•œ ๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ๋‚จ์•„์žˆ์–ด. ๐Ÿ˜…

๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ์•„๋ฌด๋ฆฌ ์ž˜ ๋งŒ๋“ค์–ด๋„, ๊ฒฐ๊ตญ ๊ฐ ํŒŒ์ผ์„ require๋‚˜ include๋กœ ๋ถˆ๋Ÿฌ์™€์•ผ ํ•˜์ž–์•„?
ํŒŒ์ผ์ด 100๊ฐœ๋ฉด require ๋ฌธ๋„ 100๊ฐœ... ์ƒ์ƒ๋งŒ ํ•ด๋„ ๋”์ฐํ•˜์ง€? ๐Ÿ˜ฑ

๐ŸŽช ์˜คํ† ๋กœ๋”ฉ์ด ๋ญ์•ผ? ์˜คํ† ๋กœ๋”ฉ(Autoloading)์€ ํ•„์š”ํ•œ ํด๋ž˜์Šค ํŒŒ์ผ์„ ์ž๋™์œผ๋กœ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๊ธฐ๋Šฅ์ด์•ผ!
ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•  ๋•Œ, PHP๊ฐ€ ์•Œ์•„์„œ ํ•ด๋‹น ํŒŒ์ผ์„ ์ฐพ์•„์„œ ๋กœ๋“œํ•ด์ฃผ๋Š” ๊ฑฐ์ง€.

๋” ์ด์ƒ require ์ง€์˜ฅ์—์„œ ๋ฒ—์–ด๋‚  ์ˆ˜ ์žˆ์–ด! ๐ŸŽ‰
๐Ÿ”น PHP์˜ ์˜คํ† ๋กœ๋”ฉ ์—ญ์‚ฌ

์˜คํ† ๋กœ๋”ฉ๋„ ์ง„ํ™” ๊ณผ์ •์„ ๊ฑฐ์ณค์–ด. ๊ฐ„๋‹จํžˆ ์‚ดํŽด๋ณด์ž!

1๋‹จ๊ณ„: __autoload() ํ•จ์ˆ˜ (PHP 5.0~7.1)
<?php
function __autoload($className)
{
    include $className . '.php';
}

// User ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ž๋™์œผ๋กœ User.php๋ฅผ ๋กœ๋“œ
$user = new User();

์ดˆ๊ธฐ ์˜คํ† ๋กœ๋”ฉ ๋ฐฉ์‹์ด์•ผ. ๊ฐ„๋‹จํ•˜์ง€๋งŒ ํ•˜๋‚˜์˜ ํ•จ์ˆ˜๋งŒ ์ •์˜ํ•  ์ˆ˜ ์žˆ์–ด์„œ ์œ ์—ฐ์„ฑ์ด ๋–จ์–ด์กŒ์–ด.
PHP 7.2๋ถ€ํ„ฐ๋Š” deprecated ๋˜์—ˆ๊ณ , PHP 8.0์—์„œ ์™„์ „ํžˆ ์ œ๊ฑฐ๋์–ด! โŒ

2๋‹จ๊ณ„: spl_autoload_register() (PHP 5.1~ํ˜„์žฌ)
<?php
spl_autoload_register(function ($className) {
    $file = str_replace('\\', '/', $className) . '.php';
    if (file_exists($file)) {
        require $file;
    }
});

// ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์˜คํ† ๋กœ๋”๋ฅผ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์Œ!
spl_autoload_register(function ($className) {
    // ๋‹ค๋ฅธ ๋กœ๋”ฉ ๋กœ์ง
});

ํ˜„์žฌ ํ‘œ์ค€ ๋ฐฉ์‹์ด์•ผ! ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์˜คํ† ๋กœ๋”๋ฅผ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ์–ด์„œ ํ›จ์”ฌ ์œ ์—ฐํ•ด์กŒ์–ด.
๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋งˆ๋‹ค ์ž์‹ ๋งŒ์˜ ์˜คํ† ๋กœ๋”๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์ง€! ๐ŸŽฏ

๐Ÿ”น ๊ฐ„๋‹จํ•œ ์˜คํ† ๋กœ๋” ๋งŒ๋“ค์–ด๋ณด๊ธฐ

์ง์ ‘ ์˜คํ† ๋กœ๋”๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋ฉด์„œ ์›๋ฆฌ๋ฅผ ์ดํ•ดํ•ด๋ณด์ž!
์ƒ๊ฐ๋ณด๋‹ค ๊ฐ„๋‹จํ•ด. ๐Ÿ˜Š

<?php
// autoload.php
spl_autoload_register(function ($className) {
    // ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๊ตฌ๋ถ„์ž๋ฅผ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ๋ถ„์ž๋กœ ๋ณ€๊ฒฝ
    // App\Models\User -> App/Models/User
    $file = str_replace('\\', DIRECTORY_SEPARATOR, $className);
    
    // .php ํ™•์žฅ์ž ์ถ”๊ฐ€
    $file = __DIR__ . '/' . $file . '.php';
    
    // ํŒŒ์ผ์ด ์กด์žฌํ•˜๋ฉด ๋กœ๋“œ
    if (file_exists($file)) {
        require $file;
    }
});

// ์ด์ œ ์ด ํŒŒ์ผ๋งŒ includeํ•˜๋ฉด ๋!
// index.php
require 'autoload.php';

use App\Models\User;
use App\Controllers\UserController;

$user = new User(); // ์ž๋™์œผ๋กœ App/Models/User.php ๋กœ๋“œ!
$controller = new UserController(); // ์ž๋™์œผ๋กœ App/Controllers/UserController.php ๋กœ๋“œ!

์–ด๋•Œ? ์‹ ๊ธฐํ•˜์ง€? ๐Ÿช„
ํด๋ž˜์Šค ์ด๋ฆ„๋งŒ ๋ณด๊ณ  ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ์ถ”์ธกํ•ด์„œ ์ž๋™์œผ๋กœ ๋กœ๋“œํ•˜๋Š” ๊ฑฐ์•ผ!

ํ•˜์ง€๋งŒ ์ด ๋ฐฉ์‹์—๋„ ๋ฌธ์ œ๊ฐ€ ์žˆ์–ด.
ํ”„๋กœ์ ํŠธ๋งˆ๋‹ค ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ๊ฐ€ ๋‹ค๋ฅด๋ฉด? ์˜คํ† ๋กœ๋”๋„ ๋งค๋ฒˆ ๋‹ค๋ฅด๊ฒŒ ๋งŒ๋“ค์–ด์•ผ ํ•ด.
๊ทธ๋ž˜์„œ ๋“ฑ์žฅํ•œ ๊ฒŒ ๋ฐ”๋กœ PSR-4 ํ‘œ์ค€์ด์•ผ! ๐ŸŒŸ

๐Ÿ“‹ PSR-4: ์˜คํ† ๋กœ๋”ฉ์˜ ํ‘œ์ค€

PSR์€ PHP Standards Recommendations์˜ ์•ฝ์ž์•ผ.
PHP-FIG(PHP Framework Interop Group)๋ผ๋Š” ๋‹จ์ฒด์—์„œ ๋งŒ๋“  PHP ์ฝ”๋”ฉ ํ‘œ์ค€์ด์ง€.

๊ทธ์ค‘์—์„œ PSR-4๋Š” ์˜คํ† ๋กœ๋”ฉ์— ๊ด€ํ•œ ํ‘œ์ค€์ด์•ผ! ๐Ÿ“œ

๐ŸŽฏ PSR-4์˜ ํ•ต์‹ฌ ๊ทœ์น™ 1. ๋„ค์ž„์ŠคํŽ˜์ด์Šค์™€ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ ์ผ์น˜
๋„ค์ž„์ŠคํŽ˜์ด์Šค์˜ ๊ฐ ๋ถ€๋ถ„์ด ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ์™€ ์ •ํ™•ํžˆ ์ผ์น˜ํ•ด์•ผ ํ•ด.

2. ํด๋ž˜์Šค ์ด๋ฆ„๊ณผ ํŒŒ์ผ ์ด๋ฆ„ ์ผ์น˜
ํด๋ž˜์Šค ์ด๋ฆ„๊ณผ ํŒŒ์ผ ์ด๋ฆ„์ด ๋Œ€์†Œ๋ฌธ์ž๊นŒ์ง€ ์ •ํ™•ํžˆ ๊ฐ™์•„์•ผ ํ•ด.

3. ๋„ค์ž„์ŠคํŽ˜์ด์Šค ํ”„๋ฆฌํ”ฝ์Šค
์ตœ์ƒ์œ„ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ํŠน์ • ๋””๋ ‰ํ† ๋ฆฌ์— ๋งคํ•‘ํ•  ์ˆ˜ ์žˆ์–ด.

4. .php ํ™•์žฅ์ž
๋ชจ๋“  ํด๋ž˜์Šค ํŒŒ์ผ์€ .php ํ™•์žฅ์ž๋ฅผ ๊ฐ€์ ธ์•ผ ํ•ด.
๐Ÿ”น PSR-4 ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ ์˜ˆ์‹œ

์‹ค์ œ๋กœ ์–ด๋–ป๊ฒŒ ๊ตฌ์กฐ๋ฅผ ์žก๋Š”์ง€ ๋ณด์ž!
์ด๊ฒŒ PSR-4์˜ ํ•ต์‹ฌ์ด์•ผ. ๐Ÿ—๏ธ

ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ:
project/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ Models/
โ”‚   โ”‚   โ”œโ”€โ”€ User.php
โ”‚   โ”‚   โ””โ”€โ”€ Post.php
โ”‚   โ”œโ”€โ”€ Controllers/
โ”‚   โ”‚   โ”œโ”€โ”€ UserController.php
โ”‚   โ”‚   โ””โ”€โ”€ PostController.php
โ”‚   โ””โ”€โ”€ Services/
โ”‚       โ””โ”€โ”€ EmailService.php
โ”œโ”€โ”€ vendor/
โ”œโ”€โ”€ composer.json
โ””โ”€โ”€ index.php

์ด ๊ตฌ์กฐ์—์„œ ๊ฐ ํŒŒ์ผ์˜ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋Š” ์ด๋ ‡๊ฒŒ ๋ผ:

<?php
// src/Models/User.php
namespace App\Models;

class User
{
    // ...
}

// src/Controllers/UserController.php
namespace App\Controllers;

class UserController
{
    // ...
}

// src/Services/EmailService.php
namespace App\Services;

class EmailService
{
    // ...
}

๋ณด์ด์ง€? ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๊ตฌ์กฐ = ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ์•ผ!
App\Models\User ํด๋ž˜์Šค๋Š” src/Models/User.php์— ์žˆ๊ณ ,
App\Controllers\UserController ํด๋ž˜์Šค๋Š” src/Controllers/UserController.php์— ์žˆ์–ด.

์ด ๊ทœ์น™๋งŒ ์ง€ํ‚ค๋ฉด ์˜คํ† ๋กœ๋”๊ฐ€ ์ž๋™์œผ๋กœ ํŒŒ์ผ์„ ์ฐพ์„ ์ˆ˜ ์žˆ์–ด! ๐ŸŽฏ

๐Ÿ”น PSR-4 ์˜คํ† ๋กœ๋” ๊ตฌํ˜„ํ•˜๊ธฐ

PSR-4 ํ‘œ์ค€์„ ๋”ฐ๋ฅด๋Š” ์˜คํ† ๋กœ๋”๋ฅผ ์ง์ ‘ ๋งŒ๋“ค์–ด๋ณด์ž!
Composer๋ฅผ ์“ฐ์ง€ ์•Š๊ณ ๋„ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋„๋ก ์ˆœ์ˆ˜ PHP๋กœ ์ž‘์„ฑํ• ๊ฒŒ.

<?php
// PSR4Autoloader.php
class PSR4Autoloader
{
    // ๋„ค์ž„์ŠคํŽ˜์ด์Šค ํ”„๋ฆฌํ”ฝ์Šค์™€ ๋ฒ ์ด์Šค ๋””๋ ‰ํ† ๋ฆฌ ๋งคํ•‘
    protected $prefixes = [];
    
    // ๋„ค์ž„์ŠคํŽ˜์ด์Šค ํ”„๋ฆฌํ”ฝ์Šค ๋“ฑ๋ก
    public function addNamespace($prefix, $baseDir)
    {
        // ๋„ค์ž„์ŠคํŽ˜์ด์Šค ํ”„๋ฆฌํ”ฝ์Šค ์ •๊ทœํ™”
        $prefix = trim($prefix, '\\') . '\\';
        
        // ๋ฒ ์ด์Šค ๋””๋ ‰ํ† ๋ฆฌ ์ •๊ทœํ™”
        $baseDir = rtrim($baseDir, DIRECTORY_SEPARATOR) . '/';
        
        // ๋ฐฐ์—ด์— ์ถ”๊ฐ€
        if (!isset($this->prefixes[$prefix])) {
            $this->prefixes[$prefix] = [];
        }
        $this->prefixes[$prefix][] = $baseDir;
    }
    
    // ์˜คํ† ๋กœ๋” ๋“ฑ๋ก
    public function register()
    {
        spl_autoload_register([$this, 'loadClass']);
    }
    
    // ํด๋ž˜์Šค ๋กœ๋“œ
    public function loadClass($className)
    {
        // ํ˜„์žฌ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ํ”„๋ฆฌํ”ฝ์Šค
        $prefix = $className;
        
        // ๋„ค์ž„์ŠคํŽ˜์ด์Šค ํ”„๋ฆฌํ”ฝ์Šค๋ฅผ ์ฐพ์„ ๋•Œ๊นŒ์ง€ ๊ฑฐ์Šฌ๋Ÿฌ ์˜ฌ๋ผ๊ฐ
        while (false !== $pos = strrpos($prefix, '\\')) {
            $prefix = substr($className, 0, $pos + 1);
            $relativeClass = substr($className, $pos + 1);
            
            // ๋งคํ•‘๋œ ํŒŒ์ผ ๋กœ๋“œ ์‹œ๋„
            $mappedFile = $this->loadMappedFile($prefix, $relativeClass);
            if ($mappedFile) {
                return $mappedFile;
            }
            
            // ๋‹ค์Œ ํ”„๋ฆฌํ”ฝ์Šค ์‹œ๋„
            $prefix = rtrim($prefix, '\\');
        }
        
        return false;
    }
    
    // ๋งคํ•‘๋œ ํŒŒ์ผ ๋กœ๋“œ
    protected function loadMappedFile($prefix, $relativeClass)
    {
        // ํ”„๋ฆฌํ”ฝ์Šค๊ฐ€ ๋“ฑ๋ก๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธ
        if (!isset($this->prefixes[$prefix])) {
            return false;
        }
        
        // ๊ฐ ๋ฒ ์ด์Šค ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ˆœํšŒ
        foreach ($this->prefixes[$prefix] as $baseDir) {
            // ์ƒ๋Œ€ ํด๋ž˜์Šค ์ด๋ฆ„์„ ํŒŒ์ผ ๊ฒฝ๋กœ๋กœ ๋ณ€ํ™˜
            $file = $baseDir
                  . str_replace('\\', '/', $relativeClass)
                  . '.php';
            
            // ํŒŒ์ผ์ด ์กด์žฌํ•˜๋ฉด ๋กœ๋“œ
            if ($this->requireFile($file)) {
                return $file;
            }
        }
        
        return false;
    }
    
    // ํŒŒ์ผ require
    protected function requireFile($file)
    {
        if (file_exists($file)) {
            require $file;
            return true;
        }
        return false;
    }
}

// ์‚ฌ์šฉ ์˜ˆ์‹œ
$loader = new PSR4Autoloader();

// App ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ src ๋””๋ ‰ํ† ๋ฆฌ์— ๋งคํ•‘
$loader->addNamespace('App', __DIR__ . '/src');

// ์˜คํ† ๋กœ๋” ๋“ฑ๋ก
$loader->register();

// ์ด์ œ ์ž๋™์œผ๋กœ ๋กœ๋“œ๋จ!
use App\Models\User;
use App\Controllers\UserController;

$user = new User();
$controller = new UserController();

์™€, ์ฝ”๋“œ๊ฐ€ ์ข€ ๊ธธ์ง€? ๐Ÿ˜…
ํ•˜์ง€๋งŒ ์ด๊ฒŒ PSR-4 ์˜คํ† ๋กœ๋”์˜ ํ•ต์‹ฌ ๋กœ์ง์ด์•ผ!

๋™์ž‘ ์›๋ฆฌ๋ฅผ ๊ฐ„๋‹จํžˆ ์„ค๋ช…ํ•˜๋ฉด:
1. ํด๋ž˜์Šค ์ด๋ฆ„์—์„œ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ํ”„๋ฆฌํ”ฝ์Šค๋ฅผ ์ฐพ์•„
2. ๋“ฑ๋ก๋œ ๋ฒ ์ด์Šค ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๊ฐ€์ ธ์™€์„œ
3. ๋‚˜๋จธ์ง€ ํด๋ž˜์Šค ๊ฒฝ๋กœ๋ฅผ ํŒŒ์ผ ๊ฒฝ๋กœ๋กœ ๋ณ€ํ™˜ํ•˜๊ณ 
4. ํ•ด๋‹น ํŒŒ์ผ์„ require ํ•˜๋Š” ๊ฑฐ์•ผ!

์‹ค์ œ๋กœ๋Š” ์ด๋ ‡๊ฒŒ ๋ณต์žกํ•˜๊ฒŒ ๋งŒ๋“ค ํ•„์š” ์—†์–ด.
์™œ๋ƒํ•˜๋ฉด Composer๊ฐ€ ์ด ๋ชจ๋“  ๊ฑธ ์ž๋™์œผ๋กœ ํ•ด์ฃผ๊ฑฐ๋“ ! ๐ŸŽ

๐ŸŽผ Composer์™€ PSR-4์˜ ์™„๋ฒฝํ•œ ์กฐํ•ฉ

์ž, ์ด์ œ ์ง„์งœ ์‹ค์ „์œผ๋กœ ๋“ค์–ด๊ฐ€๋ณด์ž!
ํ˜„๋Œ€ PHP ๊ฐœ๋ฐœ์—์„œ๋Š” ๊ฑฐ์˜ ๋ชจ๋“  ํ”„๋กœ์ ํŠธ๊ฐ€ Composer๋ฅผ ์‚ฌ์šฉํ•ด.
Composer๋Š” PHP์˜ ์˜์กด์„ฑ ๊ด€๋ฆฌ ๋„๊ตฌ์ธ๋ฐ, PSR-4 ์˜คํ† ๋กœ๋”ฉ์„ ์™„๋ฒฝํ•˜๊ฒŒ ์ง€์›ํ•ด! ๐ŸŽต

๐Ÿ’ก Composer๊ฐ€ ๋ญ์•ผ? Composer๋Š” PHP ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ์ž์•ผ.
Node.js์˜ npm, Python์˜ pip ๊ฐ™์€ ๊ฑฐ๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ผ!

โ€ข ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์„ค์น˜ ๋ฐ ๊ด€๋ฆฌ
โ€ข ์˜์กด์„ฑ ์ž๋™ ํ•ด๊ฒฐ
โ€ข PSR-4 ์˜คํ† ๋กœ๋”ฉ ์ž๋™ ์ƒ์„ฑ
โ€ข ์ „ ์„ธ๊ณ„ PHP ๊ฐœ๋ฐœ์ž๋“ค์ด ์‚ฌ์šฉํ•˜๋Š” ํ‘œ์ค€ ๋„๊ตฌ
๐Ÿ”น Composer ์„ค์น˜ํ•˜๊ธฐ

๋จผ์ € Composer๋ฅผ ์„ค์น˜ํ•ด์•ผ ํ•ด.
๊ณต์‹ ์‚ฌ์ดํŠธ(getcomposer.org)์—์„œ ๋‹ค์šด๋กœ๋“œํ•  ์ˆ˜ ์žˆ์–ด!

Windows: Composer-Setup.exe ๋‹ค์šด๋กœ๋“œ ํ›„ ์„ค์น˜
Mac/Linux: ํ„ฐ๋ฏธ๋„์—์„œ ๋‹ค์Œ ๋ช…๋ น์–ด ์‹คํ–‰
curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/local/bin/composer

์„ค์น˜๊ฐ€ ๋๋‚˜๋ฉด ํ„ฐ๋ฏธ๋„์—์„œ composer --version์„ ์ž…๋ ฅํ•ด๋ด.
๋ฒ„์ „ ์ •๋ณด๊ฐ€ ๋‚˜์˜ค๋ฉด ์„ฑ๊ณต! ๐ŸŽ‰

๐Ÿ”น composer.json ์„ค์ •ํ•˜๊ธฐ

ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ์— composer.json ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์•ผ ํ•ด.
์ด ํŒŒ์ผ์ด ํ”„๋กœ์ ํŠธ์˜ ์„ค์ •๊ณผ ์˜์กด์„ฑ์„ ๊ด€๋ฆฌํ•˜๋Š” ํ•ต์‹ฌ ํŒŒ์ผ์ด์•ผ!

{
    "name": "mycompany/myproject",
    "description": "๋‚ด ๋ฉ‹์ง„ PHP ํ”„๋กœ์ ํŠธ",
    "type": "project",
    "require": {
        "php": ">=7.4"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}

์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์€ autoload ์„น์…˜์ด์•ผ!
"App\\" ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ "src/" ๋””๋ ‰ํ† ๋ฆฌ์— ๋งคํ•‘ํ•œ๋‹ค๋Š” ๋œป์ด์ง€.

์ฆ‰, App\Models\User ํด๋ž˜์Šค๋Š” src/Models/User.php์— ์žˆ์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฑฐ์•ผ! ๐Ÿ“

โš ๏ธ ์ฃผ์˜์‚ฌํ•ญ JSON ํŒŒ์ผ์—์„œ๋Š” ๋ฐฑ์Šฌ๋ž˜์‹œ๋ฅผ ๋‘ ๋ฒˆ ์จ์•ผ ํ•ด! (\\)
์™œ๋ƒํ•˜๋ฉด ๋ฐฑ์Šฌ๋ž˜์‹œ๊ฐ€ ์ด์Šค์ผ€์ดํ”„ ๋ฌธ์ž์ด๊ธฐ ๋•Œ๋ฌธ์ด์•ผ.
"App\\" ์ด๋ ‡๊ฒŒ ์จ์•ผ ์‹ค์ œ๋กœ๋Š” "App\"๋กœ ์ธ์‹๋ผ!
๐Ÿ”น ์˜คํ† ๋กœ๋” ์ƒ์„ฑํ•˜๊ธฐ

composer.json ํŒŒ์ผ์„ ๋งŒ๋“ค์—ˆ์œผ๋ฉด, ์ด์ œ ์˜คํ† ๋กœ๋”๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•ด.
ํ„ฐ๋ฏธ๋„์—์„œ ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ๋กœ ์ด๋™ํ•œ ๋‹ค์Œ ์ด ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•ด:

composer install

๋˜๋Š” ์ด๋ฏธ composer๋ฅผ ์‚ฌ์šฉ ์ค‘์ด๋ผ๋ฉด:

composer dump-autoload

๊ทธ๋Ÿฌ๋ฉด vendor ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์ƒ๊ธฐ๊ณ , ๊ทธ ์•ˆ์— autoload.php ํŒŒ์ผ์ด ๋งŒ๋“ค์–ด์ ธ!
์ด ํŒŒ์ผ ํ•˜๋‚˜๋งŒ includeํ•˜๋ฉด ๋ชจ๋“  ์˜คํ† ๋กœ๋”ฉ์ด ์ž๋™์œผ๋กœ ์ž‘๋™ํ•ด. ๐Ÿช„

๐Ÿ”น ์‹ค์ œ ์‚ฌ์šฉ ์˜ˆ์‹œ

์ด์ œ ์‹ค์ „์—์„œ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉํ•˜๋Š”์ง€ ๋ณด์ž!
์™„์ „ํ•œ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค์–ด๋ณผ๊ฒŒ.

ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ:
myproject/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ Models/
โ”‚   โ”‚   โ”œโ”€โ”€ User.php
โ”‚   โ”‚   โ””โ”€โ”€ Post.php
โ”‚   โ”œโ”€โ”€ Controllers/
โ”‚   โ”‚   โ”œโ”€โ”€ UserController.php
โ”‚   โ”‚   โ””โ”€โ”€ PostController.php
โ”‚   โ”œโ”€โ”€ Services/
โ”‚   โ”‚   โ””โ”€โ”€ EmailService.php
โ”‚   โ””โ”€โ”€ Helpers/
โ”‚       โ””โ”€โ”€ StringHelper.php
โ”œโ”€โ”€ vendor/
โ”‚   โ””โ”€โ”€ autoload.php (Composer๊ฐ€ ์ž๋™ ์ƒ์„ฑ)
โ”œโ”€โ”€ public/
โ”‚   โ””โ”€โ”€ index.php
โ””โ”€โ”€ composer.json

๊ฐ ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ๋ณด์ž:

<?php
// src/Models/User.php
namespace App\Models;

class User
{
    private $name;
    private $email;
    
    public function __construct($name, $email)
    {
        $this->name = $name;
        $this->email = $email;
    }
    
    public function getName()
    {
        return $this->name;
    }
    
    public function getEmail()
    {
        return $this->email;
    }
}
<?php
// src/Services/EmailService.php
namespace App\Services;

class EmailService
{
    public function send($to, $subject, $message)
    {
        // ์‹ค์ œ๋กœ๋Š” ๋ฉ”์ผ ์ „์†ก ๋กœ์ง์ด ๋“ค์–ด๊ฐ€๊ฒ ์ง€๋งŒ
        // ์—ฌ๊ธฐ์„œ๋Š” ๊ฐ„๋‹จํžˆ ์ถœ๋ ฅ๋งŒ ํ• ๊ฒŒ
        echo "๐Ÿ“ง ๋ฉ”์ผ ์ „์†ก!\n";
        echo "๋ฐ›๋Š” ์‚ฌ๋žŒ: {$to}\n";
        echo "์ œ๋ชฉ: {$subject}\n";
        echo "๋‚ด์šฉ: {$message}\n";
        return true;
    }
}
<?php
// src/Controllers/UserController.php
namespace App\Controllers;

use App\Models\User;
use App\Services\EmailService;

class UserController
{
    private $emailService;
    
    public function __construct()
    {
        $this->emailService = new EmailService();
    }
    
    public function register($name, $email)
    {
        // ์‚ฌ์šฉ์ž ์ƒ์„ฑ
        $user = new User($name, $email);
        
        // ํ™˜์˜ ๋ฉ”์ผ ์ „์†ก
        $this->emailService->send(
            $user->getEmail(),
            "ํšŒ์›๊ฐ€์ž…์„ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค!",
            "{$user->getName()}๋‹˜, ๊ฐ€์ž…ํ•ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!"
        );
        
        return $user;
    }
}
<?php
// public/index.php
require __DIR__ . '/../vendor/autoload.php';

use App\Controllers\UserController;

// ์ปจํŠธ๋กค๋Ÿฌ ์ƒ์„ฑ
$controller = new UserController();

// ์‚ฌ์šฉ์ž ๋“ฑ๋ก
$user = $controller->register('ํ™๊ธธ๋™', 'hong@example.com');

echo "\nโœ… ์‚ฌ์šฉ์ž ๋“ฑ๋ก ์™„๋ฃŒ!\n";
echo "์ด๋ฆ„: " . $user->getName() . "\n";
echo "์ด๋ฉ”์ผ: " . $user->getEmail() . "\n";

๋ณด์ด์ง€? ๋”ฑ ํ•œ ์ค„๋งŒ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ผ!
require __DIR__ . '/../vendor/autoload.php';

์ด ํ•œ ์ค„์ด ๋ชจ๋“  ๋งˆ๋ฒ•์„ ์ผ์œผ์ผœ! โœจ
๋” ์ด์ƒ require๋‚˜ include๋ฅผ ์“ธ ํ•„์š”๊ฐ€ ์—†์–ด.
use๋กœ ํด๋ž˜์Šค๋ฅผ ์„ ์–ธํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ์ž๋™์œผ๋กœ ๋กœ๋“œ๋ผ!

๐ŸŽฏ Composer ์˜คํ† ๋กœ๋”ฉ์˜ ์žฅ์  โ€ข ์ž๋™ํ™”: ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ์‹ ๊ฒฝ ์“ธ ํ•„์š” ์—†์Œ
โ€ข ํ‘œ์ค€ํ™”: PSR-4 ํ‘œ์ค€์„ ์ž๋™์œผ๋กœ ๋”ฐ๋ฆ„
โ€ข ์„ฑ๋Šฅ: ํด๋ž˜์Šค๋งต ์ตœ์ ํ™”๋กœ ๋น ๋ฅธ ๋กœ๋”ฉ
โ€ข ํŽธ์˜์„ฑ: ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋„ ์ž๋™์œผ๋กœ ๋กœ๋“œ
โ€ข ์œ ์ง€๋ณด์ˆ˜: ๊ตฌ์กฐ ๋ณ€๊ฒฝ์ด ์‰ฌ์›€

๐Ÿ—๏ธ ์‹ค์ „ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ ์„ค๊ณ„

์ด๋ก ์€ ์ถฉ๋ถ„ํžˆ ๋ฐฐ์› ์œผ๋‹ˆ, ์ด์ œ ์‹ค์ „ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ๋ฅผ ์„ค๊ณ„ํ•ด๋ณด์ž!
์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ PHP ๊ฐœ๋ฐœ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•  ๋•Œ๋„ ์ด๋Ÿฐ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ข‹์•„. ๐Ÿ˜Š

๐Ÿ”น MVC ํŒจํ„ด ๊ธฐ๋ฐ˜ ๊ตฌ์กฐ

๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” MVC(Model-View-Controller) ํŒจํ„ด์„ PSR-4๋กœ ๊ตฌํ˜„ํ•ด๋ณด์ž!

project/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ Models/           # ๋ฐ์ดํ„ฐ ๋ชจ๋ธ
โ”‚   โ”‚   โ”œโ”€โ”€ User.php
โ”‚   โ”‚   โ”œโ”€โ”€ Post.php
โ”‚   โ”‚   โ””โ”€โ”€ Comment.php
โ”‚   โ”œโ”€โ”€ Controllers/      # ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง
โ”‚   โ”‚   โ”œโ”€โ”€ UserController.php
โ”‚   โ”‚   โ”œโ”€โ”€ PostController.php
โ”‚   โ”‚   โ””โ”€โ”€ CommentController.php
โ”‚   โ”œโ”€โ”€ Views/           # ํ™”๋ฉด ํ…œํ”Œ๋ฆฟ
โ”‚   โ”‚   โ”œโ”€โ”€ users/
โ”‚   โ”‚   โ”œโ”€โ”€ posts/
โ”‚   โ”‚   โ””โ”€โ”€ layouts/
โ”‚   โ”œโ”€โ”€ Services/        # ์„œ๋น„์Šค ๋ ˆ์ด์–ด
โ”‚   โ”‚   โ”œโ”€โ”€ AuthService.php
โ”‚   โ”‚   โ”œโ”€โ”€ EmailService.php
โ”‚   โ”‚   โ””โ”€โ”€ PaymentService.php
โ”‚   โ”œโ”€โ”€ Repositories/    # ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๋ ˆ์ด์–ด
โ”‚   โ”‚   โ”œโ”€โ”€ UserRepository.php
โ”‚   โ”‚   โ””โ”€โ”€ PostRepository.php
โ”‚   โ”œโ”€โ”€ Middleware/      # ๋ฏธ๋“ค์›จ์–ด
โ”‚   โ”‚   โ”œโ”€โ”€ AuthMiddleware.php
โ”‚   โ”‚   โ””โ”€โ”€ CorsMiddleware.php
โ”‚   โ”œโ”€โ”€ Helpers/         # ํ—ฌํผ ํ•จ์ˆ˜
โ”‚   โ”‚   โ”œโ”€โ”€ StringHelper.php
โ”‚   โ”‚   โ””โ”€โ”€ DateHelper.php
โ”‚   โ””โ”€โ”€ Config/          # ์„ค์ • ํŒŒ์ผ
โ”‚       โ”œโ”€โ”€ Database.php
โ”‚       โ””โ”€โ”€ App.php
โ”œโ”€โ”€ public/              # ๊ณต๊ฐœ ๋””๋ ‰ํ† ๋ฆฌ
โ”‚   โ”œโ”€โ”€ index.php
โ”‚   โ”œโ”€โ”€ css/
โ”‚   โ””โ”€โ”€ js/
โ”œโ”€โ”€ tests/               # ํ…Œ์ŠคํŠธ ์ฝ”๋“œ
โ”‚   โ”œโ”€โ”€ Unit/
โ”‚   โ””โ”€โ”€ Integration/
โ”œโ”€โ”€ vendor/              # Composer ํŒจํ‚ค์ง€
โ”œโ”€โ”€ .env                 # ํ™˜๊ฒฝ ๋ณ€์ˆ˜
โ”œโ”€โ”€ composer.json
โ””โ”€โ”€ README.md

์ด ๊ตฌ์กฐ์˜ composer.json์€ ์ด๋ ‡๊ฒŒ ์„ค์ •ํ•ด:

{
    "name": "mycompany/awesome-project",
    "description": "PSR-4 ๊ธฐ๋ฐ˜์˜ ๋ฉ‹์ง„ PHP ํ”„๋กœ์ ํŠธ",
    "type": "project",
    "require": {
        "php": ">=7.4"
    },
    "require-dev": {
        "phpunit/phpunit": "^9.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    }
}

autoload-dev๋Š” ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋งŒ ์‚ฌ์šฉํ•˜๋Š” ์˜คํ† ๋กœ๋”ฉ ์„ค์ •์ด์•ผ.
ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ๊ฐ™์€ ๊ฑด ํ”„๋กœ๋•์…˜์—์„œ ํ•„์š” ์—†์œผ๋‹ˆ๊นŒ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฑฐ์ง€! ๐ŸŽฏ

๐Ÿ”น ๋ ˆ์ด์–ด๋ณ„ ์—ญํ• ๊ณผ ์˜ˆ์‹œ

๊ฐ ๋ ˆ์ด์–ด๊ฐ€ ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€ ์‹ค์ œ ์ฝ”๋“œ๋กœ ๋ณด์ž!

๐Ÿ“ฆ Models - ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์ •์˜
<?php
namespace App\Models;

class User
{
    private $id;
    private $username;
    private $email;
    private $createdAt;
    
    public function __construct(array $data)
    {
        $this->id = $data['id'] ?? null;
        $this->username = $data['username'];
        $this->email = $data['email'];
        $this->createdAt = $data['created_at'] ?? date('Y-m-d H:i:s');
    }
    
    public function getId(): ?int
    {
        return $this->id;
    }
    
    public function getUsername(): string
    {
        return $this->username;
    }
    
    public function getEmail(): string
    {
        return $this->email;
    }
    
    public function toArray(): array
    {
        return [
            'id' => $this->id,
            'username' => $this->username,
            'email' => $this->email,
            'created_at' => $this->createdAt
        ];
    }
}
๐Ÿ—„๏ธ Repositories - ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ ‘๊ทผ
<?php
namespace App\Repositories;

use App\Models\User;
use PDO;

class UserRepository
{
    private $db;
    
    public function __construct(PDO $db)
    {
        $this->db = $db;
    }
    
    public function find(int $id): ?User
    {
        $stmt = $this->db->prepare('SELECT * FROM users WHERE id = ?');
        $stmt->execute([$id]);
        $data = $stmt->fetch(PDO::FETCH_ASSOC);
        
        return $data ? new User($data) : null;
    }
    
    public function findByEmail(string $email): ?User
    {
        $stmt = $this->db->prepare('SELECT * FROM users WHERE email = ?');
        $stmt->execute([$email]);
        $data = $stmt->fetch(PDO::FETCH_ASSOC);
        
        return $data ? new User($data) : null;
    }
    
    public function save(User $user): bool
    {
        $data = $user->toArray();
        
        if ($user->getId()) {
            // ์—…๋ฐ์ดํŠธ
            $stmt = $this->db->prepare(
                'UPDATE users SET username = ?, email = ? WHERE id = ?'
            );
            return $stmt->execute([
                $data['username'],
                $data['email'],
                $data['id']
            ]);
        } else {
            // ์ƒ์„ฑ
            $stmt = $this->db->prepare(
                'INSERT INTO users (username, email, created_at) VALUES (?, ?, ?)'
            );
            return $stmt->execute([
                $data['username'],
                $data['email'],
                $data['created_at']
            ]);
        }
    }
    
    public function delete(int $id): bool
    {
        $stmt = $this->db->prepare('DELETE FROM users WHERE id = ?');
        return $stmt->execute([$id]);
    }
}
โš™๏ธ Services - ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง
<?php
namespace App\Services;

use App\Models\User;
use App\Repositories\UserRepository;

class UserService
{
    private $userRepository;
    private $emailService;
    
    public function __construct(
        UserRepository $userRepository,
        EmailService $emailService
    ) {
        $this->userRepository = $userRepository;
        $this->emailService = $emailService;
    }
    
    public function register(string $username, string $email, string $password): User
    {
        // ์ด๋ฉ”์ผ ์ค‘๋ณต ์ฒดํฌ
        if ($this->userRepository->findByEmail($email)) {
            throw new \Exception('์ด๋ฏธ ์‚ฌ์šฉ ์ค‘์ธ ์ด๋ฉ”์ผ์ž…๋‹ˆ๋‹ค.');
        }
        
        // ์‚ฌ์šฉ์ž ์ƒ์„ฑ
        $user = new User([
            'username' => $username,
            'email' => $email
        ]);
        
        // ์ €์žฅ
        $this->userRepository->save($user);
        
        // ํ™˜์˜ ๋ฉ”์ผ ๋ฐœ์†ก
        $this->emailService->sendWelcomeEmail($user);
        
        return $user;
    }
    
    public function updateProfile(int $userId, array $data): User
    {
        $user = $this->userRepository->find($userId);
        
        if (!$user) {
            throw new \Exception('์‚ฌ์šฉ์ž๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.');
        }
        
        // ๋ฐ์ดํ„ฐ ์—…๋ฐ์ดํŠธ ๋กœ์ง
        // ...
        
        $this->userRepository->save($user);
        
        return $user;
    }
}
๐ŸŽฎ Controllers - HTTP ์š”์ฒญ ์ฒ˜๋ฆฌ
<?php
namespace App\Controllers;

use App\Services\UserService;

class UserController
{
    private $userService;
    
    public function __construct(UserService $userService)
    {
        $this->userService = $userService;
    }
    
    public function register()
    {
        try {
            // POST ๋ฐ์ดํ„ฐ ๋ฐ›๊ธฐ
            $username = $_POST['username'] ?? '';
            $email = $_POST['email'] ?? '';
            $password = $_POST['password'] ?? '';
            
            // ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
            if (empty($username) || empty($email) || empty($password)) {
                throw new \Exception('๋ชจ๋“  ํ•„๋“œ๋ฅผ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.');
            }
            
            // ์„œ๋น„์Šค ํ˜ธ์ถœ
            $user = $this->userService->register($username, $email, $password);
            
            // ์„ฑ๊ณต ์‘๋‹ต
            $this->jsonResponse([
                'success' => true,
                'message' => 'ํšŒ์›๊ฐ€์ž…์ด ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.',
                'data' => $user->toArray()
            ]);
            
        } catch (\Exception $e) {
            // ์—๋Ÿฌ ์‘๋‹ต
            $this->jsonResponse([
                'success' => false,
                'message' => $e->getMessage()
            ], 400);
        }
    }
    
    private function jsonResponse(array $data, int $statusCode = 200)
    {
        http_response_code($statusCode);
        header('Content-Type: application/json');
        echo json_encode($data, JSON_UNESCAPED_UNICODE);
        exit;
    }
}

๋ณด์ด์ง€? ๊ฐ ๋ ˆ์ด์–ด๊ฐ€ ๋ช…ํ™•ํ•œ ์—ญํ• ์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด! ๐ŸŽฏ

โ€ข Models: ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋งŒ ์ •์˜
โ€ข Repositories: ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ ‘๊ทผ๋งŒ ๋‹ด๋‹น
โ€ข Services: ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ์ฒ˜๋ฆฌ
โ€ข Controllers: HTTP ์š”์ฒญ/์‘๋‹ต ์ฒ˜๋ฆฌ

์ด๋ ‡๊ฒŒ ๋ถ„๋ฆฌํ•˜๋ฉด ์ฝ”๋“œ๊ฐ€ ๊น”๋”ํ•ด์ง€๊ณ , ํ…Œ์ŠคํŠธํ•˜๊ธฐ๋„ ์‰ฌ์›Œ์ ธ! ๐Ÿงช

๐Ÿ”น ์˜์กด์„ฑ ์ฃผ์ž…(Dependency Injection)

์œ„ ์ฝ”๋“œ์—์„œ ๋ˆˆ์น˜์ฑ˜์„ ์ˆ˜๋„ ์žˆ๋Š”๋ฐ, ๊ฐ ํด๋ž˜์Šค๊ฐ€ ํ•„์š”ํ•œ ์˜์กด์„ฑ์„ ์ƒ์„ฑ์ž๋กœ ๋ฐ›๊ณ  ์žˆ์ง€?
์ด๊ฒŒ ๋ฐ”๋กœ ์˜์กด์„ฑ ์ฃผ์ž…(DI) ํŒจํ„ด์ด์•ผ!

๐ŸŽฏ ์˜์กด์„ฑ ์ฃผ์ž…์˜ ์žฅ์  โ€ข ํ…Œ์ŠคํŠธ ์šฉ์ด: Mock ๊ฐ์ฒด๋กœ ์‰ฝ๊ฒŒ ๋Œ€์ฒด ๊ฐ€๋Šฅ
โ€ข ๊ฒฐํ•ฉ๋„ ๊ฐ์†Œ: ํด๋ž˜์Šค ๊ฐ„ ์˜์กด์„ฑ์ด ๋ช…ํ™•ํ•ด์ง
โ€ข ์œ ์—ฐ์„ฑ: ๊ตฌํ˜„์ฒด๋ฅผ ์‰ฝ๊ฒŒ ๊ต์ฒดํ•  ์ˆ˜ ์žˆ์Œ
โ€ข ์žฌ์‚ฌ์šฉ์„ฑ: ๊ฐ™์€ ํด๋ž˜์Šค๋ฅผ ๋‹ค์–‘ํ•œ ์ƒํ™ฉ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

๊ฐ„๋‹จํ•œ DI ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž:

<?php
namespace App\Core;

class Container
{
    private $bindings = [];
    private $instances = [];
    
    // ๋ฐ”์ธ๋”ฉ ๋“ฑ๋ก
    public function bind(string $abstract, callable $concrete)
    {
        $this->bindings[$abstract] = $concrete;
    }
    
    // ์‹ฑ๊ธ€ํ†ค ๋“ฑ๋ก
    public function singleton(string $abstract, callable $concrete)
    {
        $this->bind($abstract, function($container) use ($abstract, $concrete) {
            if (!isset($this->instances[$abstract])) {
                $this->instances[$abstract] = $concrete($container);
            }
            return $this->instances[$abstract];
        });
    }
    
    // ์ธ์Šคํ„ด์Šค ๊ฐ€์ ธ์˜ค๊ธฐ
    public function make(string $abstract)
    {
        if (isset($this->bindings[$abstract])) {
            return $this->bindings[$abstract]($this);
        }
        
        throw new \Exception("๋ฐ”์ธ๋”ฉ์„ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค: {$abstract}");
    }
}

// ์‚ฌ์šฉ ์˜ˆ์‹œ
$container = new Container();

// PDO ๋ฐ”์ธ๋”ฉ
$container->singleton(PDO::class, function() {
    return new PDO('mysql:host=localhost;dbname=mydb', 'user', 'pass');
});

// Repository ๋ฐ”์ธ๋”ฉ
$container->bind(UserRepository::class, function($c) {
    return new UserRepository($c->make(PDO::class));
});

// Service ๋ฐ”์ธ๋”ฉ
$container->bind(UserService::class, function($c) {
    return new UserService(
        $c->make(UserRepository::class),
        $c->make(EmailService::class)
    );
});

// Controller ๋ฐ”์ธ๋”ฉ
$container->bind(UserController::class, function($c) {
    return new UserController($c->make(UserService::class));
});

// ์‚ฌ์šฉ
$controller = $container->make(UserController::class);

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์˜์กด์„ฑ ๊ด€๋ฆฌ๊ฐ€ ํ›จ์”ฌ ์‰ฌ์›Œ์ ธ!
Laravel ๊ฐ™์€ ํ”„๋ ˆ์ž„์›Œํฌ๋„ ์ด๋Ÿฐ ๋ฐฉ์‹์œผ๋กœ ๋™์ž‘ํ•ด. ๐Ÿš€

๐Ÿ”ง ๊ณ ๊ธ‰ PSR-4 ํ™œ์šฉ ๊ธฐ๋ฒ•

๊ธฐ๋ณธ์€ ์ด์ œ ์™„๋ฒฝํ•˜๊ฒŒ ์ดํ•ดํ–ˆ์ง€?
์ด์ œ ์ข€ ๋” ๊ณ ๊ธ‰ ๊ธฐ๋ฒ•๋“ค์„ ์•Œ์•„๋ณด์ž! ๐ŸŽ“

๐Ÿ”น ์—ฌ๋Ÿฌ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๋งคํ•‘

ํ•˜๋‚˜์˜ ํ”„๋กœ์ ํŠธ์—์„œ ์—ฌ๋Ÿฌ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด.
์˜ˆ๋ฅผ ๋“ค์–ด, ํ”Œ๋Ÿฌ๊ทธ์ธ ์‹œ์Šคํ…œ์ด๋‚˜ ๋ชจ๋“ˆ ์‹œ์Šคํ…œ์„ ๋งŒ๋“ค ๋•Œ ์œ ์šฉํ•ด!

{
    "autoload": {
        "psr-4": {
            "App\\": "src/",
            "Plugins\\": "plugins/",
            "Themes\\": "themes/",
            "Admin\\": "admin/src/"
        }
    }
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด:

project/
โ”œโ”€โ”€ src/              โ†’ App\
โ”œโ”€โ”€ plugins/          โ†’ Plugins\
โ”œโ”€โ”€ themes/           โ†’ Themes\
โ””โ”€โ”€ admin/
    โ””โ”€โ”€ src/          โ†’ Admin\

๊ฐ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ๋…๋ฆฝ์ ์ธ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋ฅผ ๊ฐ€์ง€๊ฒŒ ๋ผ!
ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ฐœ๋ฐœ์ž๋Š” Plugins\ ๋„ค์ž„์ŠคํŽ˜์ด์Šค๋งŒ ์‚ฌ์šฉํ•˜๋ฉด ๋˜๋Š” ๊ฑฐ์ง€. ๐Ÿ”Œ

๐Ÿ”น ํด๋ž˜์Šค๋งต ์˜คํ† ๋กœ๋”ฉ

PSR-4๋ฅผ ๋”ฐ๋ฅด์ง€ ์•Š๋Š” ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ๋‚˜ ํŠน์ˆ˜ํ•œ ๊ฒฝ์šฐ์—๋Š” ํด๋ž˜์Šค๋งต์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด.

{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        },
        "classmap": [
            "legacy/",
            "lib/OldClass.php"
        ]
    }
}

ํด๋ž˜์Šค๋งต์€ ์ง€์ •๋œ ๋””๋ ‰ํ† ๋ฆฌ๋‚˜ ํŒŒ์ผ์„ ์Šค์บ”ํ•ด์„œ ๋ชจ๋“  ํด๋ž˜์Šค๋ฅผ ์ฐพ์•„๋‚ด!
PSR-4๋ณด๋‹ค ๋А๋ฆฌ์ง€๋งŒ, ๊ตฌ์กฐ๊ฐ€ ๋ณต์žกํ•œ ๋ ˆ๊ฑฐ์‹œ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ฉํ•  ๋•Œ ์œ ์šฉํ•ด. ๐Ÿ—บ๏ธ

๐Ÿ”น ํŒŒ์ผ ์ž๋™ ๋กœ๋“œ

ํด๋ž˜์Šค๊ฐ€ ์•„๋‹Œ ์ผ๋ฐ˜ PHP ํŒŒ์ผ(ํ—ฌํผ ํ•จ์ˆ˜ ๋“ฑ)์„ ์ž๋™์œผ๋กœ ๋กœ๋“œํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด?

{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        },
        "files": [
            "src/helpers.php",
            "src/constants.php"
        ]
    }
}
<?php
// src/helpers.php
if (!function_exists('dd')) {
    function dd(...$vars)
    {
        foreach ($vars as $var) {
            var_dump($var);
        }
        die();
    }
}

if (!function_exists('env')) {
    function env($key, $default = null)
    {
        return $_ENV[$key] ?? $default;
    }
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด autoload.php๋ฅผ ๋กœ๋“œํ•  ๋•Œ ์ด ํŒŒ์ผ๋“ค๋„ ์ž๋™์œผ๋กœ ๋กœ๋“œ๋ผ!
Laravel์˜ ํ—ฌํผ ํ•จ์ˆ˜๋“ค๋„ ์ด๋Ÿฐ ๋ฐฉ์‹์œผ๋กœ ์ œ๊ณต๋ผ. ๐Ÿ› ๏ธ

๐Ÿ”น ์ตœ์ ํ™” ๊ธฐ๋ฒ•

ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” ์˜คํ† ๋กœ๋”ฉ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•ด์•ผ ํ•ด!

1. ํด๋ž˜์Šค๋งต ์ƒ์„ฑ (๊ถŒ์žฅ)
composer dump-autoload --optimize

๋ชจ๋“  PSR-4 ํด๋ž˜์Šค๋ฅผ ์Šค์บ”ํ•ด์„œ ํด๋ž˜์Šค๋งต์„ ์ƒ์„ฑํ•ด.
ํŒŒ์ผ ์‹œ์Šคํ…œ ์ ‘๊ทผ์„ ์ค„์—ฌ์„œ ์„ฑ๋Šฅ์ด ํ–ฅ์ƒ๋ผ! โšก

2. Authoritative ํด๋ž˜์Šค๋งต (์ตœ๊ณ  ์„ฑ๋Šฅ)
composer dump-autoload --classmap-authoritative

ํด๋ž˜์Šค๋งต์— ์—†๋Š” ํด๋ž˜์Šค๋Š” ์•„์˜ˆ ์ฐพ์ง€ ์•Š์•„.
๊ฐ€์žฅ ๋น ๋ฅด์ง€๋งŒ, ์ƒˆ ํด๋ž˜์Šค๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด ๋‹ค์‹œ ์‹คํ–‰ํ•ด์•ผ ํ•ด! ๐Ÿš€

3. APCu ์บ์‹ฑ
composer dump-autoload --apcu

APCu ํ™•์žฅ์ด ์„ค์น˜๋˜์–ด ์žˆ๋‹ค๋ฉด ํด๋ž˜์Šค ๊ฒฝ๋กœ๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์บ์‹ฑํ•ด.
๋””์Šคํฌ I/O๋ฅผ ์ตœ์†Œํ™”ํ•ด์„œ ๋”์šฑ ๋นจ๋ผ์ ธ! ๐Ÿ’จ

โš ๏ธ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋Š” ์ตœ์ ํ™”ํ•˜์ง€ ๋งˆ! ์ตœ์ ํ™”๋œ ์˜คํ† ๋กœ๋”๋Š” ์ƒˆ ํด๋ž˜์Šค๋ฅผ ์ธ์‹ํ•˜์ง€ ๋ชปํ•  ์ˆ˜ ์žˆ์–ด.
๊ฐœ๋ฐœํ•  ๋•Œ๋Š” ์ผ๋ฐ˜ dump-autoload๋งŒ ์‚ฌ์šฉํ•˜๊ณ ,
๋ฐฐํฌํ•  ๋•Œ๋งŒ ์ตœ์ ํ™” ์˜ต์…˜์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ด!

๐Ÿ› ๋ฌธ์ œ ํ•ด๊ฒฐ๊ณผ ๋””๋ฒ„๊น…

PSR-4๋ฅผ ์‚ฌ์šฉํ•˜๋‹ค ๋ณด๋ฉด ๊ฐ€๋” ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์–ด.
์ž์ฃผ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋“ค๊ณผ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด์ž! ๐Ÿ”

๐Ÿ”น "Class not found" ์—๋Ÿฌ
๋ฌธ์ œ: ํด๋ž˜์Šค๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†๋‹ค๋Š” ์—๋Ÿฌ
Fatal error: Uncaught Error: Class 'App\Models\User' not found
์›์ธ๊ณผ ํ•ด๊ฒฐ:

1. ๋„ค์ž„์ŠคํŽ˜์ด์Šค์™€ ๋””๋ ‰ํ† ๋ฆฌ ๋ถˆ์ผ์น˜
// โŒ ์ž˜๋ชป๋œ ์˜ˆ
// ํŒŒ์ผ: src/Model/User.php (Models๊ฐ€ ์•„๋‹ˆ๋ผ Model!)
namespace App\Models;

// โœ… ์˜ฌ๋ฐ”๋ฅธ ์˜ˆ
// ํŒŒ์ผ: src/Models/User.php
namespace App\Models;
2. ํด๋ž˜์Šค ์ด๋ฆ„๊ณผ ํŒŒ์ผ ์ด๋ฆ„ ๋ถˆ์ผ์น˜
// โŒ ์ž˜๋ชป๋œ ์˜ˆ
// ํŒŒ์ผ: src/Models/user.php (์†Œ๋ฌธ์ž!)
class User { }

// โœ… ์˜ฌ๋ฐ”๋ฅธ ์˜ˆ
// ํŒŒ์ผ: src/Models/User.php (๋Œ€๋ฌธ์ž!)
class User { }
3. composer.json ์„ค์ • ์˜ค๋ฅ˜
// โŒ ์ž˜๋ชป๋œ ์˜ˆ
"autoload": {
    "psr-4": {
        "App": "src/"  // ๋ฐฑ์Šฌ๋ž˜์‹œ ์—†์Œ!
    }
}

// โœ… ์˜ฌ๋ฐ”๋ฅธ ์˜ˆ
"autoload": {
    "psr-4": {
        "App\\": "src/"  // ๋ฐฑ์Šฌ๋ž˜์‹œ ๋‘ ๊ฐœ!
    }
}
4. ์˜คํ† ๋กœ๋” ์žฌ์ƒ์„ฑ ํ•„์š”
composer dump-autoload
๐Ÿ”น ๋Œ€์†Œ๋ฌธ์ž ๋ฌธ์ œ

Windows๋Š” ํŒŒ์ผ ์‹œ์Šคํ…œ์ด ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š์ง€๋งŒ,
Linux/Mac์€ ๊ตฌ๋ถ„ํ•ด! ์ด๊ฒŒ ํฐ ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ์–ด. ๐Ÿ˜ฐ

โš ๏ธ ์‹ค์ œ ์‚ฌ๋ก€ Windows์—์„œ ๊ฐœ๋ฐœํ•  ๋•Œ๋Š” ์ž˜ ์ž‘๋™ํ•˜๋˜ ์ฝ”๋“œ๊ฐ€
Linux ์„œ๋ฒ„์— ๋ฐฐํฌํ•˜๋ฉด "Class not found" ์—๋Ÿฌ๊ฐ€ ๋‚˜๋Š” ๊ฒฝ์šฐ!

ํ•ด๊ฒฐ์ฑ…: ํ•ญ์ƒ ์ •ํ™•ํ•œ ๋Œ€์†Œ๋ฌธ์ž๋ฅผ ์‚ฌ์šฉํ•˜๊ณ ,
๊ฐ€๋Šฅํ•˜๋ฉด ๊ฐœ๋ฐœ ํ™˜๊ฒฝ๋„ Linux๋‚˜ Mac์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ์ข‹์•„.
๐Ÿ”น ๋””๋ฒ„๊น… ํŒ

์˜คํ† ๋กœ๋”ฉ ๋ฌธ์ œ๋ฅผ ๋””๋ฒ„๊น…ํ•˜๋Š” ์œ ์šฉํ•œ ๋ฐฉ๋ฒ•๋“ค! ๐Ÿ”ง

1. ์˜คํ† ๋กœ๋” ๋คํ”„ ํ™•์ธ
// vendor/composer/autoload_psr4.php ํŒŒ์ผ ํ™•์ธ
// ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๋งคํ•‘์ด ์˜ฌ๋ฐ”๋ฅธ์ง€ ์ฒดํฌ

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'App\\' => array($baseDir . '/src'),
);
2. ํด๋ž˜์Šค ๊ฒฝ๋กœ ์ถœ๋ ฅ
<?php
// ํŠน์ • ํด๋ž˜์Šค์˜ ํŒŒ์ผ ๊ฒฝ๋กœ ํ™•์ธ
$reflection = new ReflectionClass('App\Models\User');
echo $reflection->getFileName();
// ์ถœ๋ ฅ: /path/to/project/src/Models/User.php
3. ์˜คํ† ๋กœ๋” ์ฝœ๋ฐฑ ์ถ”๊ฐ€
<?php
spl_autoload_register(function($class) {
    echo "์˜คํ† ๋กœ๋”ฉ ์‹œ๋„: {$class}\n";
}, true, true); // prepend = true (๋จผ์ € ์‹คํ–‰)

// ์–ด๋–ค ํด๋ž˜์Šค๋ฅผ ๋กœ๋“œํ•˜๋ ค๊ณ  ํ•˜๋Š”์ง€ ํ™•์ธ ๊ฐ€๋Šฅ
4. Composer ๊ฒ€์ฆ
composer validate
composer diagnose

composer.json ํŒŒ์ผ์˜ ๋ฌธ๋ฒ• ์˜ค๋ฅ˜๋‚˜ ์„ค์ • ๋ฌธ์ œ๋ฅผ ์ฐพ์•„์ค˜!

๐ŸŒŸ ์‹ค์ „ ํ”„๋กœ์ ํŠธ: ๋ฏธ๋‹ˆ ๋ธ”๋กœ๊ทธ ์‹œ์Šคํ…œ

์ง€๊ธˆ๊นŒ์ง€ ๋ฐฐ์šด ๋‚ด์šฉ์„ ๋ชจ๋‘ ํ™œ์šฉํ•ด์„œ ์‹ค์ œ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž!
๊ฐ„๋‹จํ•œ ๋ธ”๋กœ๊ทธ ์‹œ์Šคํ…œ์„ PSR-4 ํ‘œ์ค€์œผ๋กœ ๊ตฌํ˜„ํ•ด๋ณผ๊ฒŒ. ๐Ÿ“

๐Ÿ”น ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ
blog/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ Models/
โ”‚   โ”‚   โ”œโ”€โ”€ Post.php
โ”‚   โ”‚   โ”œโ”€โ”€ User.php
โ”‚   โ”‚   โ””โ”€โ”€ Comment.php
โ”‚   โ”œโ”€โ”€ Controllers/
โ”‚   โ”‚   โ”œโ”€โ”€ PostController.php
โ”‚   โ”‚   โ””โ”€โ”€ CommentController.php
โ”‚   โ”œโ”€โ”€ Services/
โ”‚   โ”‚   โ”œโ”€โ”€ PostService.php
โ”‚   โ”‚   โ””โ”€โ”€ AuthService.php
โ”‚   โ”œโ”€โ”€ Repositories/
โ”‚   โ”‚   โ”œโ”€โ”€ PostRepository.php
โ”‚   โ”‚   โ””โ”€โ”€ CommentRepository.php
โ”‚   โ”œโ”€โ”€ Core/
โ”‚   โ”‚   โ”œโ”€โ”€ Router.php
โ”‚   โ”‚   โ”œโ”€โ”€ Request.php
โ”‚   โ”‚   โ””โ”€โ”€ Response.php
โ”‚   โ””โ”€โ”€ helpers.php
โ”œโ”€โ”€ public/
โ”‚   โ””โ”€โ”€ index.php
โ”œโ”€โ”€ views/
โ”‚   โ”œโ”€โ”€ posts/
โ”‚   โ”‚   โ”œโ”€โ”€ index.php
โ”‚   โ”‚   โ””โ”€โ”€ show.php
โ”‚   โ””โ”€โ”€ layouts/
โ”‚       โ””โ”€โ”€ main.php
โ”œโ”€โ”€ config/
โ”‚   โ””โ”€โ”€ database.php
โ”œโ”€โ”€ vendor/
โ”œโ”€โ”€ composer.json
โ””โ”€โ”€ .htaccess
๐Ÿ”น composer.json ์„ค์ •
{
    "name": "mycompany/mini-blog",
    "description": "PSR-4 ๊ธฐ๋ฐ˜ ๋ฏธ๋‹ˆ ๋ธ”๋กœ๊ทธ ์‹œ์Šคํ…œ",
    "type": "project",
    "require": {
        "php": ">=7.4"
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        },
        "files": [
            "src/helpers.php"
        ]
    }
}
๐Ÿ”น ํ•ต์‹ฌ ์ฝ”๋“œ ๊ตฌํ˜„
<?php
// src/Models/Post.php
namespace App\Models;

class Post
{
    private $id;
    private $title;
    private $content;
    private $authorId;
    private $createdAt;
    
    public function __construct(array $data)
    {
        $this->id = $data['id'] ?? null;
        $this->title = $data['title'];
        $this->content = $data['content'];
        $this->authorId = $data['author_id'];
        $this->createdAt = $data['created_at'] ?? date('Y-m-d H:i:s');
    }
    
    public function getId(): ?int
    {
        return $this->id;
    }
    
    public function getTitle(): string
    {
        return $this->title;
    }
    
    public function getContent(): string
    {
        return $this->content;
    }
    
    public function getExcerpt(int $length = 150): string
    {
        if (mb_strlen($this->content) <= $length) {
            return $this->content;
        }
        return mb_substr($this->content, 0, $length) . '...';
    }
    
    public function toArray(): array
    {
        return [
            'id' => $this->id,
            'title' => $this->title,
            'content' => $this->content,
            'author_id' => $this->authorId,
            'created_at' => $this->createdAt
        ];
    }
}
<?php
// src/Repositories/PostRepository.php
namespace App\Repositories;

use App\Models\Post;
use PDO;

class PostRepository
{
    private $db;
    
    public function __construct(PDO $db)
    {
        $this->db = $db;
    }
    
    public function findAll(int $limit = 10, int $offset = 0): array
    {
        $stmt = $this->db->prepare(
            'SELECT * FROM posts ORDER BY created_at DESC LIMIT ? OFFSET ?'
        );
        $stmt->execute([$limit, $offset]);
        
        $posts = [];
        while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
            $posts[] = new Post($row);
        }
        
        return $posts;
    }
    
    public function find(int $id): ?Post
    {
        $stmt = $this->db->prepare('SELECT * FROM posts WHERE id = ?');
        $stmt->execute([$id]);
        $data = $stmt->fetch(PDO::FETCH_ASSOC);
        
        return $data ? new Post($data) : null;
    }
    
    public function save(Post $post): bool
    {
        $data = $post->toArray();
        
        if ($post->getId()) {
            $stmt = $this->db->prepare(
                'UPDATE posts SET title = ?, content = ? WHERE id = ?'
            );
            return $stmt->execute([
                $data['title'],
                $data['content'],
                $data['id']
            ]);
        } else {
            $stmt = $this->db->prepare(
                'INSERT INTO posts (title, content, author_id, created_at) 
                 VALUES (?, ?, ?, ?)'
            );
            return $stmt->execute([
                $data['title'],
                $data['content'],
                $data['author_id'],
                $data['created_at']
            ]);
        }
    }
    
    public function delete(int $id): bool
    {
        $stmt = $this->db->prepare('DELETE FROM posts WHERE id = ?');
        return $stmt->execute([$id]);
    }
}
<?php
// src/Services/PostService.php
namespace App\Services;

use App\Models\Post;
use App\Repositories\PostRepository;

class PostService
{
    private $postRepository;
    
    public function __construct(PostRepository $postRepository)
    {
        $this->postRepository = $postRepository;
    }
    
    public function getAllPosts(int $page = 1, int $perPage = 10): array
    {
        $offset = ($page - 1) * $perPage;
        return $this->postRepository->findAll($perPage, $offset);
    }
    
    public function getPost(int $id): ?Post
    {
        return $this->postRepository->find($id);
    }
    
    public function createPost(string $title, string $content, int $authorId): Post
    {
        // ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
        if (empty($title) || empty($content)) {
            throw new \InvalidArgumentException('์ œ๋ชฉ๊ณผ ๋‚ด์šฉ์€ ํ•„์ˆ˜์ž…๋‹ˆ๋‹ค.');
        }
        
        if (mb_strlen($title) > 200) {
            throw new \InvalidArgumentException('์ œ๋ชฉ์€ 200์ž๋ฅผ ์ดˆ๊ณผํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.');
        }
        
        // ํฌ์ŠคํŠธ ์ƒ์„ฑ
        $post = new Post([
            'title' => $title,
            'content' => $content,
            'author_id' => $authorId
        ]);
        
        // ์ €์žฅ
        $this->postRepository->save($post);
        
        return $post;
    }
    
    public function updatePost(int $id, string $title, string $content): Post
    {
        $post = $this->getPost($id);
        
        if (!$post) {
            throw new \Exception('ํฌ์ŠคํŠธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.');
        }
        
        // ์—…๋ฐ์ดํŠธ ๋กœ์ง
        // (์‹ค์ œ๋กœ๋Š” Post ๋ชจ๋ธ์— setter ๋ฉ”์„œ๋“œ๊ฐ€ ํ•„์š”)
        
        $this->postRepository->save($post);
        
        return $post;
    }
    
    public function deletePost(int $id): bool
    {
        return $this->postRepository->delete($id);
    }
}
<?php
// src/Controllers/PostController.php
namespace App\Controllers;

use App\Services\PostService;
use App\Core\Request;
use App\Core\Response;

class PostController
{
    private $postService;
    
    public function __construct(PostService $postService)
    {
        $this->postService = $postService;
    }
    
    public function index(Request $request): Response
    {
        $page = $request->get('page', 1);
        $posts = $this->postService->getAllPosts($page);
        
        return Response::view('posts/index', [
            'posts' => $posts,
            'page' => $page
        ]);
    }
    
    public function show(Request $request, int $id): Response
    {
        $post = $this->postService->getPost($id);
        
        if (!$post) {
            return Response::notFound('ํฌ์ŠคํŠธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.');
        }
        
        return Response::view('posts/show', [
            'post' => $post
        ]);
    }
    
    public function create(Request $request): Response
    {
        try {
            $title = $request->post('title');
            $content = $request->post('content');
            $authorId = $request->session('user_id');
            
            $post = $this->postService->createPost($title, $content, $authorId);
            
            return Response::redirect('/posts/' . $post->getId())
                ->with('success', 'ํฌ์ŠคํŠธ๊ฐ€ ์ž‘์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.');
                
        } catch (\Exception $e) {
            return Response::back()
                ->with('error', $e->getMessage());
        }
    }
}
<?php
// public/index.php
require __DIR__ . '/../vendor/autoload.php';

use App\Core\Router;
use App\Core\Request;
use App\Controllers\PostController;
use App\Services\PostService;
use App\Repositories\PostRepository;

// ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ
$db = new PDO('mysql:host=localhost;dbname=blog', 'user', 'pass');

// ์˜์กด์„ฑ ์ฃผ์ž…
$postRepository = new PostRepository($db);
$postService = new PostService($postRepository);
$postController = new PostController($postService);

// ๋ผ์šฐํ„ฐ ์„ค์ •
$router = new Router();

$router->get('/', [$postController, 'index']);
$router->get('/posts/{id}', [$postController, 'show']);
$router->post('/posts', [$postController, 'create']);

// ์š”์ฒญ ์ฒ˜๋ฆฌ
$request = Request::createFromGlobals();
$response = $router->dispatch($request);
$response->send();

์™„๋ฒฝํ•œ PSR-4 ๊ตฌ์กฐ์˜ ๋ธ”๋กœ๊ทธ ์‹œ์Šคํ…œ์ด ์™„์„ฑ๋์–ด! ๐ŸŽ‰

์ด ์ฝ”๋“œ์˜ ์žฅ์ ์„ ๋ณด์ž:
โœ… ๋ช…ํ™•ํ•œ ๋„ค์ž„์ŠคํŽ˜์ด์Šค ๊ตฌ์กฐ
โœ… ์ž๋™ ์˜คํ† ๋กœ๋”ฉ
โœ… ๋ ˆ์ด์–ด๋ณ„ ์—ญํ•  ๋ถ„๋ฆฌ
โœ… ์˜์กด์„ฑ ์ฃผ์ž…
โœ… ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅํ•œ ๊ตฌ์กฐ
โœ… ํ™•์žฅ ๊ฐ€๋Šฅํ•œ ์„ค๊ณ„

์žฌ๋Šฅ๋„ท์—์„œ PHP ๊ฐœ๋ฐœ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•  ๋•Œ๋„ ์ด๋Ÿฐ ๊ตฌ์กฐ๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค๋ฉด
์˜๋ขฐ์ธ๋“ค์ด ์ฝ”๋“œ ํ’ˆ์งˆ์„ ๋†’์ด ํ‰๊ฐ€ํ•  ๊ฑฐ์•ผ! ๐Ÿ’ฏ

๐Ÿ“š PSR ํ‘œ์ค€ ์‹œ๋ฆฌ์ฆˆ

PSR-4 ์™ธ์—๋„ ์•Œ์•„๋‘๋ฉด ์ข‹์€ PSR ํ‘œ์ค€๋“ค์ด ์žˆ์–ด!
๊ฐ„๋‹จํžˆ ์†Œ๊ฐœํ•ด์ค„๊ฒŒ. ๐ŸŽฏ

PSR-1: Basic Coding Standard ๊ธฐ๋ณธ ์ฝ”๋”ฉ ํ‘œ์ค€์ด์•ผ.

โ€ข ํŒŒ์ผ์€ โ€ข ํŒŒ์ผ์€ UTF-8 without BOM ์ธ์ฝ”๋”ฉ
โ€ข ํด๋ž˜์Šค ์ด๋ฆ„์€ PascalCase
โ€ข ๋ฉ”์„œ๋“œ ์ด๋ฆ„์€ camelCase
โ€ข ์ƒ์ˆ˜๋Š” UPPER_CASE
PSR-2: Coding Style Guide (deprecated, PSR-12๋กœ ๋Œ€์ฒด) ์ฝ”๋”ฉ ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ์•ผ.

โ€ข ๋“ค์—ฌ์“ฐ๊ธฐ๋Š” 4์นธ ์ŠคํŽ˜์ด์Šค
โ€ข ํ•œ ์ค„์€ 120์ž ์ดํ•˜ ๊ถŒ์žฅ
โ€ข ์ค‘๊ด„ํ˜ธ ์œ„์น˜ ๊ทœ์น™
โ€ข ๋„ค์ž„์ŠคํŽ˜์ด์Šค์™€ use ์„ ์–ธ ๊ทœ์น™
PSR-3: Logger Interface
๋กœ๊น… ์ธํ„ฐํŽ˜์ด์Šค ํ‘œ์ค€์ด์•ผ.

<?php
interface LoggerInterface
{
    public function emergency($message, array $context = []);
    public function alert($message, array $context = []);
    public function critical($message, array $context = []);
    public function error($message, array $context = []);
    public function warning($message, array $context = []);
    public function notice($message, array $context = []);
    public function info($message, array $context = []);
    public function debug($message, array $context = []);
    public function log($level, $message, array $context = []);
}
PSR-7: HTTP Message Interface HTTP ๋ฉ”์‹œ์ง€ ์ธํ„ฐํŽ˜์ด์Šค์•ผ.

โ€ข RequestInterface
โ€ข ResponseInterface
โ€ข ServerRequestInterface
โ€ข UriInterface

ํ˜„๋Œ€ PHP ํ”„๋ ˆ์ž„์›Œํฌ๋“ค์ด ์ด ํ‘œ์ค€์„ ๋”ฐ๋ผ!
PSR-11: Container Interface
์˜์กด์„ฑ ์ฃผ์ž… ์ปจํ…Œ์ด๋„ˆ ์ธํ„ฐํŽ˜์ด์Šค์•ผ.

<?php
interface ContainerInterface
{
    public function get(string $id);
    public function has(string $id): bool;
}
PSR-12: Extended Coding Style PSR-2๋ฅผ ํ™•์žฅํ•œ ์ตœ์‹  ์ฝ”๋”ฉ ์Šคํƒ€์ผ ํ‘œ์ค€์ด์•ผ.

โ€ข PHP 7.0+ ๊ธฐ๋Šฅ ์ง€์›
โ€ข ํƒ€์ž… ์„ ์–ธ ๊ทœ์น™
โ€ข ์ต๋ช… ํด๋ž˜์Šค ๊ทœ์น™
โ€ข ํด๋กœ์ € ๊ทœ์น™

์ด๋Ÿฐ ํ‘œ์ค€๋“ค์„ ๋”ฐ๋ฅด๋ฉด ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค๊ณผ ํ˜‘์—…ํ•  ๋•Œ ํ›จ์”ฌ ์ˆ˜์›”ํ•ด์ ธ!
ํŠนํžˆ ์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ๋‚˜ ํŒ€ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ํ•„์ˆ˜์•ผ. ๐Ÿค

๐ŸŽ“ ํ•™์Šต ๋ฆฌ์†Œ์Šค์™€ ๋‹ค์Œ ๋‹จ๊ณ„

์—ฌ๊ธฐ๊นŒ์ง€ ์ฝ์—ˆ๋‹ค๋ฉด ์ •๋ง ๋Œ€๋‹จํ•ด! ๐Ÿ‘
PSR-4์™€ ์˜คํ† ๋กœ๋”ฉ์˜ ๋ชจ๋“  ๊ฒƒ์„ ๋ฐฐ์› ์–ด.
์ด์ œ ๋” ๊นŠ์ด ๊ณต๋ถ€ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์ด๋Ÿฐ ๊ฒƒ๋“ค์„ ์ถ”์ฒœํ•ด!

๐Ÿ”— ์ถ”์ฒœ ํ•™์Šต ์ž๋ฃŒ ๊ณต์‹ ๋ฌธ์„œ:
โ€ข PHP-FIG ๊ณต์‹ ์‚ฌ์ดํŠธ: php-fig.org
โ€ข PSR-4 ๋ช…์„ธ: php-fig.org/psr/psr-4
โ€ข Composer ๊ณต์‹ ๋ฌธ์„œ: getcomposer.org/doc

ํ”„๋ ˆ์ž„์›Œํฌ ์†Œ์Šค ์ฝ”๋“œ:
โ€ข Laravel: github.com/laravel/framework
โ€ข Symfony: github.com/symfony/symfony
โ€ข Slim: github.com/slimphp/Slim

์—ฐ์Šต ํ”„๋กœ์ ํŠธ:
โ€ข ๋‚˜๋งŒ์˜ ๋ฏธ๋‹ˆ ํ”„๋ ˆ์ž„์›Œํฌ ๋งŒ๋“ค๊ธฐ
โ€ข PSR-4 ๊ธฐ๋ฐ˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ฐœ๋ฐœ
โ€ข ์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ ๊ธฐ์—ฌํ•˜๊ธฐ
๐Ÿ”น ๋‹ค์Œ ๋‹จ๊ณ„๋กœ ๋‚˜์•„๊ฐ€๊ธฐ
1๋‹จ๊ณ„: ๊ธฐ๋ณธ ๋งˆ์Šคํ„ฐ โœ… ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์™„๋ฒฝ ์ดํ•ด
โœ… PSR-4 ๊ทœ์น™ ์ˆ™์ง€
โœ… Composer ์‚ฌ์šฉ๋ฒ•
โœ… ๊ธฐ๋ณธ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ ์„ค๊ณ„
2๋‹จ๊ณ„: ์‹ค์ „ ์ ์šฉ โœ… MVC ํŒจํ„ด ๊ตฌํ˜„
โœ… ์˜์กด์„ฑ ์ฃผ์ž… ํ™œ์šฉ
โœ… ๋ ˆ์ด์–ด๋“œ ์•„ํ‚คํ…์ฒ˜
โœ… ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ
3๋‹จ๊ณ„: ๊ณ ๊ธ‰ ๊ธฐ๋ฒ• โœ… ๋””์ž์ธ ํŒจํ„ด ์ ์šฉ
โœ… SOLID ์›์น™ ์ค€์ˆ˜
โœ… ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์•„ํ‚คํ…์ฒ˜
โœ… ์„ฑ๋Šฅ ์ตœ์ ํ™”
4๋‹จ๊ณ„: ํ”„๋ ˆ์ž„์›Œํฌ ๋ ˆ๋ฒจ โœ… ๋‚˜๋งŒ์˜ ํ”„๋ ˆ์ž„์›Œํฌ ๊ฐœ๋ฐœ
โœ… ํŒจํ‚ค์ง€ ๋ฐฐํฌ (Packagist)
โœ… ์˜คํ”ˆ์†Œ์Šค ๊ธฐ์—ฌ
โœ… ์ปค๋ฎค๋‹ˆํ‹ฐ ํ™œ๋™

๐Ÿ’ก ์‹ค๋ฌด ํŒ๊ณผ ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค

๋งˆ์ง€๋ง‰์œผ๋กœ ์‹ค๋ฌด์—์„œ ์ •๋ง ์œ ์šฉํ•œ ํŒ๋“ค์„ ๊ณต์œ ํ• ๊ฒŒ!
์ด๊ฑด ๊ฒฝํ—˜์—์„œ ๋‚˜์˜จ ์ง„์งœ ๋…ธํ•˜์šฐ์•ผ. ๐ŸŽฏ

โœจ ๋„ค์ด๋ฐ ์ปจ๋ฒค์…˜ โ€ข ๋„ค์ž„์ŠคํŽ˜์ด์Šค: ํšŒ์‚ฌ๋ช…\ํ”„๋กœ์ ํŠธ๋ช…\๊ธฐ๋Šฅ
์˜ˆ: Acme\Blog\Controllers

โ€ข ์ธํ„ฐํŽ˜์ด์Šค: ~Interface ์ ‘๋ฏธ์‚ฌ
์˜ˆ: UserRepositoryInterface

โ€ข ์ถ”์ƒ ํด๋ž˜์Šค: Abstract~ ์ ‘๋‘์‚ฌ
์˜ˆ: AbstractController

โ€ข ํŠธ๋ ˆ์ดํŠธ: ~Trait ์ ‘๋ฏธ์‚ฌ
์˜ˆ: TimestampTrait
๐Ÿ—‚๏ธ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ ํŒ โ€ข ๊ธฐ๋Šฅ๋ณ„ ๋ถ„๋ฆฌ: ํฐ ํ”„๋กœ์ ํŠธ๋Š” ๊ธฐ๋Šฅ๋ณ„๋กœ ๋ชจ๋“ˆํ™”
src/Blog/, src/Shop/, src/Forum/

โ€ข ๊ณตํ†ต ์ฝ”๋“œ: Common์ด๋‚˜ Shared ๋””๋ ‰ํ† ๋ฆฌ์—
src/Common/Helpers/, src/Shared/Traits/

โ€ข ์ธํ„ฐํŽ˜์ด์Šค ๋ถ„๋ฆฌ: Contracts ๋””๋ ‰ํ† ๋ฆฌ์—
src/Contracts/RepositoryInterface.php
โšก ์„ฑ๋Šฅ ์ตœ์ ํ™” โ€ข ํ”„๋กœ๋•์…˜: ํ•ญ์ƒ ์ตœ์ ํ™”๋œ ์˜คํ† ๋กœ๋” ์‚ฌ์šฉ
โ€ข ๊ฐœ๋ฐœ: ์ผ๋ฐ˜ ์˜คํ† ๋กœ๋”๋กœ ๋น ๋ฅธ ๊ฐœ๋ฐœ
โ€ข ์บ์‹ฑ: OPcache, APCu ํ™œ์šฉ
โ€ข ์ง€์—ฐ ๋กœ๋”ฉ: ํ•„์š”ํ•  ๋•Œ๋งŒ ํด๋ž˜์Šค ๋กœ๋“œ
๐Ÿ”’ ๋ณด์•ˆ ๊ณ ๋ ค์‚ฌํ•ญ โ€ข ๊ณต๊ฐœ ๋””๋ ‰ํ† ๋ฆฌ: public/ ์™ธ๋ถ€๋Š” ์›น ์ ‘๊ทผ ์ฐจ๋‹จ
โ€ข ํ™˜๊ฒฝ ๋ณ€์ˆ˜: .env ํŒŒ์ผ๋กœ ๋ฏผ๊ฐ ์ •๋ณด ๊ด€๋ฆฌ
โ€ข ์˜์กด์„ฑ: composer update ์‹ ์ค‘ํ•˜๊ฒŒ
โ€ข ๊ฒ€์ฆ: ์‚ฌ์šฉ์ž ์ž…๋ ฅ์€ ํ•ญ์ƒ ๊ฒ€์ฆ
โš ๏ธ ํ”ํ•œ ์‹ค์ˆ˜๋“ค 1. ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์˜คํƒ€
App\Model\User (โŒ) โ†’ App\Models\User (โœ…)

2. ํŒŒ์ผ๋ช… ๋Œ€์†Œ๋ฌธ์ž
user.php (โŒ) โ†’ User.php (โœ…)

3. ๋ฐฑ์Šฌ๋ž˜์‹œ ๋ˆ„๋ฝ
"App": "src/" (โŒ) โ†’ "App\\": "src/" (โœ…)

4. ์˜คํ† ๋กœ๋” ๋ฏธ๊ฐฑ์‹ 
์ƒˆ ํด๋ž˜์Šค ์ถ”๊ฐ€ ํ›„ dump-autoload ์•ˆ ํ•จ

5. ์ˆœํ™˜ ์˜์กด์„ฑ
A๊ฐ€ B๋ฅผ ์ฐธ์กฐํ•˜๊ณ  B๊ฐ€ A๋ฅผ ์ฐธ์กฐํ•˜๋Š” ๊ตฌ์กฐ

๐ŸŽฌ ๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ

์™€! ์ •๋ง ๊ธด ์—ฌ์ •์ด์—ˆ์ง€? ๐Ÿ˜…
์—ฌ๊ธฐ๊นŒ์ง€ ์ฝ์€ ๋„ˆ๋Š” ์ด์ œ PHP ๋„ค์ž„์ŠคํŽ˜์ด์Šค์™€ PSR-4 ์˜คํ† ๋กœ๋”ฉ์˜ ์ „๋ฌธ๊ฐ€์•ผ! ๐ŸŽ“

๐ŸŽฏ ํ•ต์‹ฌ ์ •๋ฆฌ 1. ๋„ค์ž„์ŠคํŽ˜์ด์Šค
โ€ข ํด๋ž˜์Šค ์ด๋ฆ„ ์ถฉ๋Œ ๋ฐฉ์ง€
โ€ข ๋…ผ๋ฆฌ์  ๊ทธ๋ฃนํ™”
โ€ข ์ฝ”๋“œ ๊ตฌ์กฐํ™”

2. PSR-4 ์˜คํ† ๋กœ๋”ฉ
โ€ข ๋„ค์ž„์ŠคํŽ˜์ด์Šค = ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ
โ€ข ํด๋ž˜์Šค๋ช… = ํŒŒ์ผ๋ช…
โ€ข ์ž๋™ ํŒŒ์ผ ๋กœ๋”ฉ

3. Composer
โ€ข ์˜์กด์„ฑ ๊ด€๋ฆฌ
โ€ข ์ž๋™ ์˜คํ† ๋กœ๋” ์ƒ์„ฑ
โ€ข ํŒจํ‚ค์ง€ ์ƒํƒœ๊ณ„

4. ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ
โ€ข ๋ ˆ์ด์–ด ๋ถ„๋ฆฌ
โ€ข ์˜์กด์„ฑ ์ฃผ์ž…
โ€ข ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅํ•œ ์„ค๊ณ„

์ด์ œ ๋„ˆ๋Š” ํ˜„๋Œ€์ ์ธ PHP ๊ฐœ๋ฐœ์˜ ๊ธฐ์ดˆ๋ฅผ ์™„๋ฒฝํ•˜๊ฒŒ ์ดํ•ดํ–ˆ์–ด!
Laravel, Symfony ๊ฐ™์€ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ฝ”๋“œ๋„ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์„ ๊ฑฐ์•ผ.

์žฌ๋Šฅ๋„ท์—์„œ PHP ๊ฐœ๋ฐœ ์žฌ๋Šฅ์„ ๊ณต์œ ํ•˜๊ฑฐ๋‚˜ ๋ฐฐ์šธ ๋•Œ๋„
์ด๋Ÿฐ ํ‘œ์ค€ํ™”๋œ ๊ตฌ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ›จ์”ฌ ์ „๋ฌธ์ ์œผ๋กœ ๋ณด์ผ ๊ฑฐ์•ผ! ๐Ÿ’ผ

๊ธฐ์–ตํ•ด, ์ข‹์€ ์ฝ”๋“œ๋Š” ๋‹จ์ˆœํžˆ ์ž‘๋™ํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ
์ฝ๊ธฐ ์‰ฝ๊ณ , ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ์‰ฝ๊ณ , ํ™•์žฅํ•˜๊ธฐ ์‰ฌ์šด ์ฝ”๋“œ์•ผ! โœจ

์ด ๊ธ€์ด ๋„์›€์ด ๋๋‹ค๋ฉด, ์ง์ ‘ ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค์–ด๋ณด๋ฉด์„œ ์—ฐ์Šตํ•ด๋ด.
์ฒ˜์Œ์—” ์–ด์ƒ‰ํ•˜๊ฒ ์ง€๋งŒ, ๊ธˆ๋ฐฉ ์ต์ˆ™ํ•ด์งˆ ๊ฑฐ์•ผ!

ํ™”์ดํŒ…! ๐Ÿš€ ๋„ˆ๋Š” ํ•  ์ˆ˜ ์žˆ์–ด!

๐ŸŽ‰ ์ถ•ํ•˜ํ•ฉ๋‹ˆ๋‹ค! PSR-4 ๋งˆ์Šคํ„ฐ๊ฐ€ ๋˜์…จ์Šต๋‹ˆ๋‹ค ์ด์ œ ํ˜„๋Œ€์ ์ธ PHP ๊ฐœ๋ฐœ์˜ ์„ธ๊ณ„๋กœ! ์‹œ์ž‘ ์—ฐ์Šต ๋งˆ์Šคํ„ฐ ์ „๋ฌธ๊ฐ€

๐Ÿ’ป Happy Coding! ๐Ÿ’ป

์งˆ๋ฌธ์ด๋‚˜ ํ”ผ๋“œ๋ฐฑ์ด ์žˆ๋‹ค๋ฉด ์–ธ์ œ๋“  ์žฌ๋Šฅ๋„ท ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ ๊ณต์œ ํ•ด์ค˜!
ํ•จ๊ป˜ ์„ฑ์žฅํ•˜๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜์ž! ๐ŸŒฑ

๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0
๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค.