Ver3.0 ๐ PHP ๋ค์์คํ์ด์ค์ ์คํ ๋ก๋ฉ, PSR-4 ํ์ค์ผ๋ก ์ฝ๋ ๊ตฌ์กฐ๋ฅผ ์๋ฒฝํ๊ฒ ์ ๋ฆฌํ๋ ๋ฒ

๐ PHP ๋ค์์คํ์ด์ค์ ์คํ ๋ก๋ฉ, PSR-4 ํ์ค์ผ๋ก ์ฝ๋ ๊ตฌ์กฐ๋ฅผ ์๋ฒฝํ๊ฒ ์ ๋ฆฌํ๋ ๋ฒ
๋ณต์กํ PHP ํ๋ก์ ํธ๋ฅผ ๊น๋ํ๊ฒ ๊ด๋ฆฌํ๋ ํ๋์ ์ธ ๋ฐฉ๋ฒ
๐ฌ ์ผ, ๋ PHP๋ก ํ๋ก์ ํธ ๋ง๋ค๋ค๊ฐ ํ์ผ์ด ์์ญ ๊ฐ, ์๋ฐฑ ๊ฐ๋ก ๋์ด๋๋ฉด์ "์ด๊ฑฐ ์ด๋ ์๋๋ผ?" ํ๋ฉด์ ํค๋งจ ์ ์์ง? ๐
ํด๋์ค ์ด๋ฆ์ด ๊ฒน์ณ์ ์๋ฌ ๋๊ณ , require ๋ฌธ์ฅ์ด ํ์ผ๋ง๋ค ์์ญ ์ค์ฉ ๋์ด๋๊ณ ... ์ง์ง ๋จธ๋ฆฌ ์ํ์ง?
์ค๋์ ๊ทธ๋ฐ ๊ณ ๋ฏผ์ ์น ๋ ๋ ค์ค ๋ค์์คํ์ด์ค(Namespace)์ ์คํ ๋ก๋ฉ(Autoloading), ๊ทธ๋ฆฌ๊ณ PSR-4 ํ์ค์ ๋ํด ์น๊ตฌ์ฒ๋ผ ํธํ๊ฒ ์ด์ผ๊ธฐํด๋ณผ๊ฒ! ๐ฏ
์ด ๊ธ ํ๋๋ฉด PHP ํ๋ก์ ํธ ๊ตฌ์กฐํ์ A to Z๋ฅผ ์๋ฒฝํ๊ฒ ์ดํดํ ์ ์์ ๊ฑฐ์ผ. ์ฌ๋ฅ๋ท์์ PHP ๊ฐ๋ฐ ์ฌ๋ฅ์ ๊ณต์ ํ๊ฑฐ๋ ๋ฐฐ์ฐ๋ ค๋ ์ฌ๋๋ค์๊ฒ๋ ๋ฑ ํ์ํ ๋ด์ฉ์ด๋๊น ๋๊น์ง ์ง์ค! ๐ฅ
๐ค ์ ๋ค์์คํ์ด์ค๊ฐ ํ์ํ ๊น?
์, ๋จผ์ ๋ค์์คํ์ด์ค๊ฐ ์ ํ์ํ์ง๋ถํฐ ์ดํดํด๋ณด์.
PHP ์ด์ฐฝ๊ธฐ์๋ ํ๋ก์ ํธ ๊ท๋ชจ๊ฐ ์์์ด. ํ์ผ ๋ช ๊ฐ, ํด๋์ค ๋ช ๊ฐ๋ฉด ์ถฉ๋ถํ์ง.
๊ทธ๋ฐ๋ฐ ํ๋ก์ ํธ๊ฐ ์ปค์ง๋ฉด์ ๋ฌธ์ ๊ฐ ์๊ธฐ๊ธฐ ์์ํ์ด. ๐ฐ
๋๊ฐ 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๊ฐ ๋๋ ๊ฑฐ์ผ.
๋ฐฑ์ฌ๋์(\)๋ก ๊ณ์ธต์ ๊ตฌ๋ถํ๋๋ฐ, ์ด๊ฑด ๋ง์น ํด๋ ๊ตฌ์กฐ์ฒ๋ผ ์๊ฐํ๋ฉด ๋ผ! ๐
โข ๋ฐฑ์ฌ๋์(\)๋ก ๊ณ์ธต ๊ตฌ๋ถ
โข ์ผ๋ฐ์ ์ผ๋ก ํ์ฌ๋ช ์ด๋ ํ๋ก์ ํธ๋ช ์ผ๋ก ์์ (์: App, MyCompany)
โข ์๋ฏธ ์๋ ์ด๋ฆ ์ฌ์ฉ (Models, Controllers, Services ๋ฑ)
๋ค๋ฅธ ํ์ผ์์ ๋ค์์คํ์ด์ค์ ์๋ ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด ์ด๋ป๊ฒ ํด์ผ ํ ๊น?
ํฌ๊ฒ ์ธ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์์ด!
<?php
$user = new \App\Models\User();
echo $user->getName();
๋งจ ์์ ๋ฐฑ์ฌ๋์(\)๋ฅผ ๋ถ์ฌ์ ์ ์ฒด ๊ฒฝ๋ก๋ฅผ ๋ค ์จ์ฃผ๋ ๋ฐฉ๋ฒ์ด์ผ.
ํ์คํ์ง๋ง ๋งค๋ฒ ์ฐ๊ธฐ์ ์ข ๊ธธ์ง? ๐
<?php
use App\Models\User;
$user = new User();
echo $user->getName();
use ํค์๋๋ก ๋ฏธ๋ฆฌ ์ ์ธํด๋๋ฉด ์งง์ ์ด๋ฆ์ผ๋ก ์ฌ์ฉํ ์ ์์ด!
๊ฐ์ฅ ๋ง์ด ์ฐ๋ ๋ฐฉ๋ฒ์ด๊ณ , ์ฝ๋๋ ๊น๋ํด์ ธ. โจ
<?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};
ํจ์ฌ ๊น๋ํ์ง? ๐
์ฝ๋ ์ค ์๋ ์ค๊ณ , ๊ฐ๋
์ฑ๋ ์ข์์ ธ!
๐ฏ ๋ค์์คํ์ด์ค ๊ณ ๊ธ ํ์ฉ๋ฒ
๊ธฐ๋ณธ์ ์ด์ ์์์ผ๋, ์ข ๋ ๊น์ด ๋ค์ด๊ฐ๋ณผ๊น?
์ค์ ์์ ์ ์ฉํ ๊ณ ๊ธ ๊ธฐ๋ฒ๋ค์ ์๋ ค์ค๊ฒ! ๐
๋ค์์คํ์ด์ค๋ ์ฌ๋ฌ ๋จ๊ณ๋ก ์ค์ฒฉํ ์ ์์ด.
ํ๋ก์ ํธ ๊ตฌ์กฐ๋ฅผ ๋ ์ธ๋ฐํ๊ฒ ๋๋ ์ ์์ง!
<?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;
}
}
๋ฐ๋์ ์์ ๋ฐฑ์ฌ๋์(\)๋ฅผ ๋ถ์ด๊ฑฐ๋ 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๊ฐ... ์์๋ง ํด๋ ๋์ฐํ์ง? ๐ฑ
ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ ค๊ณ ํ ๋, PHP๊ฐ ์์์ ํด๋น ํ์ผ์ ์ฐพ์์ ๋ก๋ํด์ฃผ๋ ๊ฑฐ์ง.
๋ ์ด์ require ์ง์ฅ์์ ๋ฒ์ด๋ ์ ์์ด! ๐
์คํ ๋ก๋ฉ๋ ์งํ ๊ณผ์ ์ ๊ฑฐ์ณค์ด. ๊ฐ๋จํ ์ดํด๋ณด์!
<?php
function __autoload($className)
{
include $className . '.php';
}
// User ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ฉด ์๋์ผ๋ก User.php๋ฅผ ๋ก๋
$user = new User();
์ด๊ธฐ ์คํ ๋ก๋ฉ ๋ฐฉ์์ด์ผ. ๊ฐ๋จํ์ง๋ง ํ๋์ ํจ์๋ง ์ ์ํ ์ ์์ด์ ์ ์ฐ์ฑ์ด ๋จ์ด์ก์ด.
PHP 7.2๋ถํฐ๋ deprecated ๋์๊ณ , PHP 8.0์์ ์์ ํ ์ ๊ฑฐ๋์ด! โ
<?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๋ ์คํ ๋ก๋ฉ์ ๊ดํ ํ์ค์ด์ผ! ๐
๋ค์์คํ์ด์ค์ ๊ฐ ๋ถ๋ถ์ด ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ์ ์ ํํ ์ผ์นํด์ผ ํด.
2. ํด๋์ค ์ด๋ฆ๊ณผ ํ์ผ ์ด๋ฆ ์ผ์น
ํด๋์ค ์ด๋ฆ๊ณผ ํ์ผ ์ด๋ฆ์ด ๋์๋ฌธ์๊น์ง ์ ํํ ๊ฐ์์ผ ํด.
3. ๋ค์์คํ์ด์ค ํ๋ฆฌํฝ์ค
์ต์์ ๋ค์์คํ์ด์ค๋ฅผ ํน์ ๋๋ ํ ๋ฆฌ์ ๋งคํํ ์ ์์ด.
4. .php ํ์ฅ์
๋ชจ๋ ํด๋์ค ํ์ผ์ .php ํ์ฅ์๋ฅผ ๊ฐ์ ธ์ผ ํด.
์ค์ ๋ก ์ด๋ป๊ฒ ๊ตฌ์กฐ๋ฅผ ์ก๋์ง ๋ณด์!
์ด๊ฒ 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 ํ์ค์ ๋ฐ๋ฅด๋ ์คํ ๋ก๋๋ฅผ ์ง์ ๋ง๋ค์ด๋ณด์!
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 ์คํ ๋ก๋ฉ์ ์๋ฒฝํ๊ฒ ์ง์ํด! ๐ต
Node.js์ npm, Python์ pip ๊ฐ์ ๊ฑฐ๋ผ๊ณ ์๊ฐํ๋ฉด ๋ผ!
โข ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์น ๋ฐ ๊ด๋ฆฌ
โข ์์กด์ฑ ์๋ ํด๊ฒฐ
โข PSR-4 ์คํ ๋ก๋ฉ ์๋ ์์ฑ
โข ์ ์ธ๊ณ PHP ๊ฐ๋ฐ์๋ค์ด ์ฌ์ฉํ๋ ํ์ค ๋๊ตฌ
๋จผ์ Composer๋ฅผ ์ค์นํด์ผ ํด.
๊ณต์ ์ฌ์ดํธ(getcomposer.org)์์ ๋ค์ด๋ก๋ํ ์ ์์ด!
Mac/Linux: ํฐ๋ฏธ๋์์ ๋ค์ ๋ช ๋ น์ด ์คํ
curl -sS https://getcomposer.org/installer | php sudo mv composer.phar /usr/local/bin/composer
์ค์น๊ฐ ๋๋๋ฉด ํฐ๋ฏธ๋์์ composer --version์ ์
๋ ฅํด๋ด.
๋ฒ์ ์ ๋ณด๊ฐ ๋์ค๋ฉด ์ฑ๊ณต! ๐
ํ๋ก์ ํธ ๋ฃจํธ์ 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์ ์์ด์ผ ํ๋ค๋ ๊ฑฐ์ผ! ๐
์๋ํ๋ฉด ๋ฐฑ์ฌ๋์๊ฐ ์ด์ค์ผ์ดํ ๋ฌธ์์ด๊ธฐ ๋๋ฌธ์ด์ผ.
"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๋ก ํด๋์ค๋ฅผ ์ ์ธํ๊ธฐ๋ง ํ๋ฉด ์๋์ผ๋ก ๋ก๋๋ผ!
โข ํ์คํ: PSR-4 ํ์ค์ ์๋์ผ๋ก ๋ฐ๋ฆ
โข ์ฑ๋ฅ: ํด๋์ค๋งต ์ต์ ํ๋ก ๋น ๋ฅธ ๋ก๋ฉ
โข ํธ์์ฑ: ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ์๋์ผ๋ก ๋ก๋
โข ์ ์ง๋ณด์: ๊ตฌ์กฐ ๋ณ๊ฒฝ์ด ์ฌ์
๐๏ธ ์ค์ ํ๋ก์ ํธ ๊ตฌ์กฐ ์ค๊ณ
์ด๋ก ์ ์ถฉ๋ถํ ๋ฐฐ์ ์ผ๋, ์ด์ ์ค์ ํ๋ก์ ํธ ๊ตฌ์กฐ๋ฅผ ์ค๊ณํด๋ณด์!
์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์ PHP ๊ฐ๋ฐ ์ฌ๋ฅ์ ๊ณต์ ํ ๋๋ ์ด๋ฐ ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ๋ฉด ์ข์. ๐
๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๋ 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๋ ๊ฐ๋ฐ ํ๊ฒฝ์์๋ง ์ฌ์ฉํ๋ ์คํ ๋ก๋ฉ ์ค์ ์ด์ผ.
ํ
์คํธ ์ฝ๋ ๊ฐ์ ๊ฑด ํ๋ก๋์
์์ ํ์ ์์ผ๋๊น ๋ถ๋ฆฌํ๋ ๊ฑฐ์ง! ๐ฏ
๊ฐ ๋ ์ด์ด๊ฐ ์ด๋ค ์ญํ ์ ํ๋์ง ์ค์ ์ฝ๋๋ก ๋ณด์!
<?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
];
}
}
<?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]);
}
}
<?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;
}
}
<?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 ์์ฒญ/์๋ต ์ฒ๋ฆฌ
์ด๋ ๊ฒ ๋ถ๋ฆฌํ๋ฉด ์ฝ๋๊ฐ ๊น๋ํด์ง๊ณ , ํ
์คํธํ๊ธฐ๋ ์ฌ์์ ธ! ๐งช
์ ์ฝ๋์์ ๋์น์ฑ์ ์๋ ์๋๋ฐ, ๊ฐ ํด๋์ค๊ฐ ํ์ํ ์์กด์ฑ์ ์์ฑ์๋ก ๋ฐ๊ณ ์์ง?
์ด๊ฒ ๋ฐ๋ก ์์กด์ฑ ์ฃผ์
(DI) ํจํด์ด์ผ!
โข ๊ฒฐํฉ๋ ๊ฐ์: ํด๋์ค ๊ฐ ์์กด์ฑ์ด ๋ช ํํด์ง
โข ์ ์ฐ์ฑ: ๊ตฌํ์ฒด๋ฅผ ์ฝ๊ฒ ๊ต์ฒดํ ์ ์์
โข ์ฌ์ฌ์ฉ์ฑ: ๊ฐ์ ํด๋์ค๋ฅผ ๋ค์ํ ์ํฉ์์ ์ฌ์ฉ ๊ฐ๋ฅ
๊ฐ๋จํ 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์ ํฌํผ ํจ์๋ค๋ ์ด๋ฐ ๋ฐฉ์์ผ๋ก ์ ๊ณต๋ผ. ๐ ๏ธ
ํ๋ก๋์ ํ๊ฒฝ์์๋ ์คํ ๋ก๋ฉ ์ฑ๋ฅ์ ์ต์ ํํด์ผ ํด!
composer dump-autoload --optimize
๋ชจ๋ PSR-4 ํด๋์ค๋ฅผ ์ค์บํด์ ํด๋์ค๋งต์ ์์ฑํด.
ํ์ผ ์์คํ
์ ๊ทผ์ ์ค์ฌ์ ์ฑ๋ฅ์ด ํฅ์๋ผ! โก
composer dump-autoload --classmap-authoritative
ํด๋์ค๋งต์ ์๋ ํด๋์ค๋ ์์ ์ฐพ์ง ์์.
๊ฐ์ฅ ๋น ๋ฅด์ง๋ง, ์ ํด๋์ค๋ฅผ ์ถ๊ฐํ๋ฉด ๋ค์ ์คํํด์ผ ํด! ๐
composer dump-autoload --apcu
APCu ํ์ฅ์ด ์ค์น๋์ด ์๋ค๋ฉด ํด๋์ค ๊ฒฝ๋ก๋ฅผ ๋ฉ๋ชจ๋ฆฌ์ ์บ์ฑํด.
๋์คํฌ I/O๋ฅผ ์ต์ํํด์ ๋์ฑ ๋นจ๋ผ์ ธ! ๐จ
๊ฐ๋ฐํ ๋๋ ์ผ๋ฐ dump-autoload๋ง ์ฌ์ฉํ๊ณ ,
๋ฐฐํฌํ ๋๋ง ์ต์ ํ ์ต์ ์ ์ฌ์ฉํด์ผ ํด!
๐ ๋ฌธ์ ํด๊ฒฐ๊ณผ ๋๋ฒ๊น
PSR-4๋ฅผ ์ฌ์ฉํ๋ค ๋ณด๋ฉด ๊ฐ๋ ๋ฌธ์ ๊ฐ ์๊ธธ ์ ์์ด.
์์ฃผ ๋ฐ์ํ๋ ๋ฌธ์ ๋ค๊ณผ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์์๋ณด์! ๐
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์ ๊ตฌ๋ถํด! ์ด๊ฒ ํฐ ๋ฌธ์ ๊ฐ ๋ ์ ์์ด. ๐ฐ
Linux ์๋ฒ์ ๋ฐฐํฌํ๋ฉด "Class not found" ์๋ฌ๊ฐ ๋๋ ๊ฒฝ์ฐ!
ํด๊ฒฐ์ฑ : ํญ์ ์ ํํ ๋์๋ฌธ์๋ฅผ ์ฌ์ฉํ๊ณ ,
๊ฐ๋ฅํ๋ฉด ๊ฐ๋ฐ ํ๊ฒฝ๋ Linux๋ Mac์ ์ฌ์ฉํ๋ ๊ฒ ์ข์.
์คํ ๋ก๋ฉ ๋ฌธ์ ๋ฅผ ๋๋ฒ๊น ํ๋ ์ ์ฉํ ๋ฐฉ๋ฒ๋ค! ๐ง
// vendor/composer/autoload_psr4.php ํ์ผ ํ์ธ
// ๋ค์์คํ์ด์ค ๋งคํ์ด ์ฌ๋ฐ๋ฅธ์ง ์ฒดํฌ
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'App\\' => array($baseDir . '/src'),
);
<?php
// ํน์ ํด๋์ค์ ํ์ผ ๊ฒฝ๋ก ํ์ธ
$reflection = new ReflectionClass('App\Models\User');
echo $reflection->getFileName();
// ์ถ๋ ฅ: /path/to/project/src/Models/User.php
<?php
spl_autoload_register(function($class) {
echo "์คํ ๋ก๋ฉ ์๋: {$class}\n";
}, true, true); // prepend = true (๋จผ์ ์คํ)
// ์ด๋ค ํด๋์ค๋ฅผ ๋ก๋ํ๋ ค๊ณ ํ๋์ง ํ์ธ ๊ฐ๋ฅ
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
{
"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 ํ์ค๋ค์ด ์์ด!
๊ฐ๋จํ ์๊ฐํด์ค๊ฒ. ๐ฏ
โข ํ์ผ์ โข ํ์ผ์ UTF-8 without BOM ์ธ์ฝ๋ฉ
โข ํด๋์ค ์ด๋ฆ์ PascalCase
โข ๋ฉ์๋ ์ด๋ฆ์ camelCase
โข ์์๋ UPPER_CASE
โข ๋ค์ฌ์ฐ๊ธฐ๋ 4์นธ ์คํ์ด์ค
โข ํ ์ค์ 120์ ์ดํ ๊ถ์ฅ
โข ์ค๊ดํธ ์์น ๊ท์น
โข ๋ค์์คํ์ด์ค์ use ์ ์ธ ๊ท์น
๋ก๊น ์ธํฐํ์ด์ค ํ์ค์ด์ผ.
<?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 = []);
}
โข RequestInterface
โข ResponseInterface
โข ServerRequestInterface
โข UriInterface
ํ๋ PHP ํ๋ ์์ํฌ๋ค์ด ์ด ํ์ค์ ๋ฐ๋ผ!
์์กด์ฑ ์ฃผ์ ์ปจํ ์ด๋ ์ธํฐํ์ด์ค์ผ.
<?php
interface ContainerInterface
{
public function get(string $id);
public function has(string $id): bool;
}
โข 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 ๊ธฐ๋ฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๊ฐ๋ฐ
โข ์คํ์์ค ํ๋ก์ ํธ ๊ธฐ์ฌํ๊ธฐ
โ PSR-4 ๊ท์น ์์ง
โ Composer ์ฌ์ฉ๋ฒ
โ ๊ธฐ๋ณธ ํ๋ก์ ํธ ๊ตฌ์กฐ ์ค๊ณ
โ ์์กด์ฑ ์ฃผ์ ํ์ฉ
โ ๋ ์ด์ด๋ ์ํคํ ์ฒ
โ ํ ์คํธ ์ฝ๋ ์์ฑ
โ SOLID ์์น ์ค์
โ ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ
โ ์ฑ๋ฅ ์ต์ ํ
โ ํจํค์ง ๋ฐฐํฌ (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 ํ์ฉ
โข ์ง์ฐ ๋ก๋ฉ: ํ์ํ ๋๋ง ํด๋์ค ๋ก๋
โข ํ๊ฒฝ ๋ณ์: .env ํ์ผ๋ก ๋ฏผ๊ฐ ์ ๋ณด ๊ด๋ฆฌ
โข ์์กด์ฑ: composer update ์ ์คํ๊ฒ
โข ๊ฒ์ฆ: ์ฌ์ฉ์ ์ ๋ ฅ์ ํญ์ ๊ฒ์ฆ
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 ์คํ ๋ก๋ฉ์ ์ ๋ฌธ๊ฐ์ผ! ๐
โข ํด๋์ค ์ด๋ฆ ์ถฉ๋ ๋ฐฉ์ง
โข ๋ ผ๋ฆฌ์ ๊ทธ๋ฃนํ
โข ์ฝ๋ ๊ตฌ์กฐํ
2. PSR-4 ์คํ ๋ก๋ฉ
โข ๋ค์์คํ์ด์ค = ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ
โข ํด๋์ค๋ช = ํ์ผ๋ช
โข ์๋ ํ์ผ ๋ก๋ฉ
3. Composer
โข ์์กด์ฑ ๊ด๋ฆฌ
โข ์๋ ์คํ ๋ก๋ ์์ฑ
โข ํจํค์ง ์ํ๊ณ
4. ํ๋ก์ ํธ ๊ตฌ์กฐ
โข ๋ ์ด์ด ๋ถ๋ฆฌ
โข ์์กด์ฑ ์ฃผ์
โข ํ ์คํธ ๊ฐ๋ฅํ ์ค๊ณ
์ด์ ๋๋ ํ๋์ ์ธ PHP ๊ฐ๋ฐ์ ๊ธฐ์ด๋ฅผ ์๋ฒฝํ๊ฒ ์ดํดํ์ด!
Laravel, Symfony ๊ฐ์ ํ๋ ์์ํฌ์ ์ฝ๋๋ ์ดํดํ ์ ์์ ๊ฑฐ์ผ.
์ฌ๋ฅ๋ท์์ PHP ๊ฐ๋ฐ ์ฌ๋ฅ์ ๊ณต์ ํ๊ฑฐ๋ ๋ฐฐ์ธ ๋๋
์ด๋ฐ ํ์คํ๋ ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ๋ฉด ํจ์ฌ ์ ๋ฌธ์ ์ผ๋ก ๋ณด์ผ ๊ฑฐ์ผ! ๐ผ
๊ธฐ์ตํด, ์ข์ ์ฝ๋๋ ๋จ์ํ ์๋ํ๋ ์ฝ๋๊ฐ ์๋๋ผ
์ฝ๊ธฐ ์ฝ๊ณ , ์ ์ง๋ณด์ํ๊ธฐ ์ฝ๊ณ , ํ์ฅํ๊ธฐ ์ฌ์ด ์ฝ๋์ผ! โจ
์ด ๊ธ์ด ๋์์ด ๋๋ค๋ฉด, ์ง์ ํ๋ก์ ํธ๋ฅผ ๋ง๋ค์ด๋ณด๋ฉด์ ์ฐ์ตํด๋ด.
์ฒ์์ ์ด์ํ๊ฒ ์ง๋ง, ๊ธ๋ฐฉ ์ต์ํด์ง ๊ฑฐ์ผ!
ํ์ดํ
! ๐ ๋๋ ํ ์ ์์ด!
๐ป Happy Coding! ๐ป
์ง๋ฌธ์ด๋ ํผ๋๋ฐฑ์ด ์๋ค๋ฉด ์ธ์ ๋ ์ฌ๋ฅ๋ท ์ปค๋ฎค๋ํฐ์์ ๊ณต์ ํด์ค!
ํจ๊ป ์ฑ์ฅํ๋ ๊ฐ๋ฐ์๊ฐ ๋์! ๐ฑ
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.