Ver3.5 ๐๏ธ Symfony ์ปดํฌ๋ํธ ๊ธฐ๋ฐ ์ํคํ ์ฒ์์์กด์ฑ ์ฃผ์ ์ปจํ ์ด๋ ํ์ฉ

๐๏ธ Symfony ์ปดํฌ๋ํธ ๊ธฐ๋ฐ ์ํคํ
์ฒ์
์์กด์ฑ ์ฃผ์
์ปจํ
์ด๋ ํ์ฉ
๐ค ใ ใ ใ ๋ ๋ค ์ข์๋ฐ, Symfony๋ ์ปดํฌ๋ํธ ๋จ์๋ก ์ชผ๊ฐ์ ์ธ ์ ์์ด์ ์ง์ง ์ ์ฐํจ ์ฉ์ด. ๊ทธ๋ฆฌ๊ณ Laravel๋ ์ฌ์ค Symfony ์ปดํฌ๋ํธ ๊ธฐ๋ฐ์ด์ผ ใทใท
PHP ์ํ๊ณ์์ Symfony๋ ๋จ์ํ ํ๋ ์์ํฌ๊ฐ ์๋๋๋ค.
๋ง์น ๋ ๊ณ ๋ธ๋ก์ฒ๋ผ ํ์ํ ์ปดํฌ๋ํธ๋ง ๊ณจ๋ผ์ ์กฐ๋ฆฝํ ์ ์๋ ์ํคํ
์ฒ ์ฒ ํ์ ๊ฐ์ง ํ๋ซํผ์ด์์.
Laravel, Drupal, Magento ๊ฐ์ ์ ๋ช
ํ PHP ํ๋ ์์ํฌ๋ค๋ Symfony ์ปดํฌ๋ํธ๋ฅผ ๋ด๋ถ์ ์ผ๋ก ์ฌ์ฉํ๊ณ ์๋ค๋ ์ฌ์ค, ์๊ณ ๊ณ์
จ๋์? ๐ฒ
์ค๋์ Symfony์ ํต์ฌ ์ค์ ํต์ฌ์ธ ์ปดํฌ๋ํธ ๊ธฐ๋ฐ ์ํคํ
์ฒ์ ์์กด์ฑ ์ฃผ์
(DI) ์ปจํ
์ด๋์ ๋ํด ์ง์ง ๊น๊ฒ ํํค์ณ๋ณผ๊ฒ์.
์ฝ๋๋ ๋ณด๊ณ , ๊ฐ๋
๋ ์ก๊ณ , ์ค๋ฌด์์ ์ด๋ป๊ฒ ์ฐ๋์ง๊น์ง โ ์์ ํํจํค์ง๋ก ๊ฐ๋๋ค ใฑใฑ ๐ฅ
Symfony๋ 2005๋
Fabien Potencier๊ฐ ๋ง๋ PHP ํ๋ ์์ํฌ์ธ๋ฐ์,
์ฒ์๋ถํฐ "๋ชจ๋๋ฆฌ์ ํ๋ ์์ํฌ๊ฐ ์๋, ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์ปดํฌ๋ํธ ์งํฉ"์ผ๋ก ์ค๊ณ๋์ด์.
์ด๊ฒ ์ง์ง ํ์ ์ ์ธ ๋ถ๋ถ์ด์์ ในใ
๐ฅ
๋จ์ผ ์ฑ ์ ์์น ๋์จํ ๊ฒฐํฉ ๋์ ์์ง๋ ์ฌ์ฌ์ฉ์ฑ
๊ฐ ์ปดํฌ๋ํธ๋ ํ๋์ ๋ช ํํ ์ญํ ๋ง ๋ด๋นํ๊ณ ,
๋ค๋ฅธ ์ปดํฌ๋ํธ์ ๋ํ ์์กด์ฑ์ ์ต์ํํด์ ๋ ๋ฆฝ์ ์ผ๋ก ์ฌ์ฉํ ์ ์์ด์.
| ์ปดํฌ๋ํธ | ์ญํ | ํจํค์ง๋ช |
|---|---|---|
| DependencyInjection | ์์กด์ฑ ์ฃผ์ ์ปจํ ์ด๋ | symfony/dependency-injection |
| HttpKernel | HTTP ์์ฒญ/์๋ต ์ฒ๋ฆฌ | symfony/http-kernel |
| Routing | URL ๋ผ์ฐํ | symfony/routing |
| EventDispatcher | ์ด๋ฒคํธ ์์คํ | symfony/event-dispatcher |
| Console | CLI ๋ช ๋ น์ด ์ฒ๋ฆฌ | symfony/console |
| Validator | ๋ฐ์ดํฐ ์ ํจ์ฑ ๊ฒ์ฌ | symfony/validator |
| Form | ํผ ์์ฑ ๋ฐ ์ฒ๋ฆฌ | symfony/form |
| Security | ์ธ์ฆ/์ธ๊ฐ | symfony/security-core |
| Cache | ์บ์ฑ ์ถ์ํ | symfony/cache |
| Serializer | ์ง๋ ฌํ/์ญ์ง๋ ฌํ | symfony/serializer |
๐ค ใดใด! ํ์ํ ๊ฒ๋ง ๊ณจ๋ผ์ ์ค์นํ๋ฉด ๋ผ. composer require symfony/routing ์ด๋ฐ ์์ผ๋ก ๋ฑ ํ์ํ ๊ฒ๋ง! ๊ทธ๋์ ๋ง์ดํฌ๋ก ํ๋ ์์ํฌ ๋ง๋ค ๋๋ Symfony ์ปดํฌ๋ํธ ์ ใ ใ
์ค์ ๋ก Symfony ์ปดํฌ๋ํธ๋ค์ Composer๋ฅผ ํตํด ๊ฐ๋ณ์ ์ผ๋ก ์ค์นํ ์ ์์ด์.
์ ์ฒด Symfony ํ๋ ์์ํฌ๋ฅผ ์ค์นํ์ง ์์๋, ํ์ํ ์ปดํฌ๋ํธ๋ง ๊ฐ์ ธ๋ค ์ธ ์ ์๋ค๋ ๊ฒ ์ง์ง ๊ฐ์ ์ด์์.
์๋ฅผ ๋ค์ด Laravel์ ๋ด๋ถ์ ์ผ๋ก symfony/http-foundation, symfony/routing, symfony/console ๋ฑ์ ์ฌ์ฉํ๊ณ ์์ด์.
Drupal 8 ์ด์๋ Symfony ์ปดํฌ๋ํธ๋ฅผ ๋๊ฑฐ ์ฑํํ๊ณ ์. ์ด๊ฒ ๋ฐ๋ก Symfony๊ฐ "PHP ์ํ๊ณ์ ์ธํ๋ผ"๋ผ๊ณ ๋ถ๋ฆฌ๋ ์ด์ ์
๋๋ค ๐ช
์์กด์ฑ ์ฃผ์
... ์ด๋ฆ๋ง ๋ค์ผ๋ฉด ๋ญ๊ฐ ์ด๋ ต๊ฒ ๋๊ปด์ง์ฃ ? ใ
ใ
ใ
๊ทผ๋ฐ ๊ฐ๋
์์ฒด๋ ์๊ฐ๋ณด๋ค ์ฌํํด์. ๊ฐ์ด ์ดํด๋ด์!
// โ ๋์ ์์ - ๊ฐํ ๊ฒฐํฉ(Tight Coupling)
class UserService {
private $db;
public function __construct() {
// ๋ด๋ถ์์ ์ง์ ์์ฑ - ์ด๊ฒ ๋ฌธ์ !
$this->db = new MySQLDatabase('localhost', 'root', 'password');
}
public function findUser(int $id): array {
return $this->db->query("SELECT * FROM users WHERE id = ?", [$id]);
}
}
// ์ฌ์ฉ
$service = new UserService(); // DB ์ค์ ์ด ํด๋์ค ์์ ๋ฐํ์์ ใ
ใ
1. ํ ์คํธ ๋ถ๊ฐ โ ๋จ์ ํ ์คํธ ์ ์ค์ DB ์ฐ๊ฒฐ์ด ํ์ํจ
2. ์ ์ฐ์ฑ ์์ โ DB๋ฅผ PostgreSQL๋ก ๋ฐ๊พธ๋ ค๋ฉด ํด๋์ค ๋ด๋ถ๋ฅผ ์์ ํด์ผ ํจ
3. ์ฌ์ฌ์ฉ ์ด๋ ค์ โ ๋ค๋ฅธ DB ์ค์ ์ผ๋ก ์ฌ์ฌ์ฉ ๋ถ๊ฐ
4. ๋จ์ผ ์ฑ ์ ์์น ์๋ฐ โ ์๋น์ค๊ฐ DB ์์ฑ๊น์ง ๋ด๋น
// โ
์ข์ ์์ - ์์กด์ฑ ์ฃผ์
(Dependency Injection)
// ์ธํฐํ์ด์ค ์ ์
interface DatabaseInterface {
public function query(string $sql, array $params = []): array;
}
// ๊ตฌํ์ฒด
class MySQLDatabase implements DatabaseInterface {
public function __construct(
private string $host,
private string $user,
private string $password
) {}
public function query(string $sql, array $params = []): array {
// MySQL ์ฟผ๋ฆฌ ์คํ
return [];
}
}
// ์๋น์ค - ์ธ๋ถ์์ ์์กด์ฑ์ ์ฃผ์
๋ฐ์!
class UserService {
public function __construct(
private DatabaseInterface $db // ์ธํฐํ์ด์ค์ ์์กด
) {}
public function findUser(int $id): array {
return $this->db->query("SELECT * FROM users WHERE id = ?", [$id]);
}
}
// ์ฌ์ฉ - ์ธ๋ถ์์ ์กฐ๋ฆฝ
$db = new MySQLDatabase('localhost', 'root', 'password');
$service = new UserService($db); // ์ฃผ์
!
// ํ
์คํธ ์์๋ Mock ๊ฐ์ฒด ์ฃผ์
๊ฐ๋ฅ!
$mockDb = new MockDatabase();
$testService = new UserService($mockDb); // ํ
์คํธ ์ฌ์์ง ใทใท
๐ค ๋ง์ ใ ใ ใ ๊ทธ๋์ DI ์ปจํ ์ด๋๊ฐ ๋ฑ์ฅํ๋ ๊ฑฐ์ผ! ์ปจํ ์ด๋๊ฐ ์์์ ๋ค ์กฐ๋ฆฝํด์ค ใฑใฑ
Symfony์ DependencyInjection ์ปดํฌ๋ํธ๋ PHP ์ํ๊ณ์์ ๊ฐ์ฅ ๊ฐ๋ ฅํ๊ณ ์ฑ์ํ DI ์ปจํ
์ด๋ ์ค ํ๋์์.
์ค์น๋ถํฐ ์ค์ ์ฌ์ฉ๊น์ง ๋จ๊ณ๋ณ๋ก ์ดํด๋ณผ๊ฒ์!
composer require symfony/dependency-injection
composer require symfony/config # ์ค์ ํ์ผ ๋ก๋ฉ์ฉ (์ ํ)
composer require symfony/yaml # YAML ์ค์ ํ์ผ์ฉ (์ ํ)
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
// ์ปจํ
์ด๋ ์์ฑ
$container = new ContainerBuilder();
// ์๋น์ค ๋ฑ๋ก - Database
$container->register('database', MySQLDatabase::class)
->addArgument('localhost')
->addArgument('root')
->addArgument('secret_password');
// ์๋น์ค ๋ฑ๋ก - Mailer
$container->register('mailer', SmtpMailer::class)
->addArgument('smtp.example.com')
->addArgument(587);
// ์๋น์ค ๋ฑ๋ก - UserService (๋ค๋ฅธ ์๋น์ค์ ์์กด)
$container->register('user_service', UserService::class)
->addArgument(new Reference('database')) // database ์๋น์ค ์ฐธ์กฐ
->addArgument(new Reference('mailer')); // mailer ์๋น์ค ์ฐธ์กฐ
// ์ปจํ
์ด๋ ์ปดํ์ผ (์ต์ ํ)
$container->compile();
// ์๋น์ค ๊ฐ์ ธ์ค๊ธฐ
$userService = $container->get('user_service');
// ์ปจํ
์ด๋๊ฐ ์์์ database, mailer ์์ฑํด์ ์ฃผ์
ํด์ค! ๐
์ง์ฐ ๋ก๋ฉ(Lazy Loading) โ ์ค์ ๋ก ํ์ํ ๋๋ง ์๋น์ค ์ธ์คํด์ค ์์ฑ
์ฑ๊ธํค ๊ด๋ฆฌ โ ๊ธฐ๋ณธ์ ์ผ๋ก ์๋น์ค๋ ํ ๋ฒ๋ง ์์ฑ๋๊ณ ์ฌ์ฌ์ฉ๋จ
์๋ ์์ด์ด๋ง โ ํ์ ํํธ ๊ธฐ๋ฐ์ผ๋ก ์์กด์ฑ ์๋ ํด๊ฒฐ
์ปดํ์ผ ์ต์ ํ โ ์ปดํ์ผ ์ ์ต์ ํ๋ PHP ์ฝ๋ ์์ฑ
PHP ์ฝ๋๋ก ์ง์ ๋ฑ๋กํ๋ ๊ฒ๋ ์ข์ง๋ง, ์ค๋ฌด์์๋ YAML ์ค์ ํ์ผ์ ๋ ๋ง์ด ์จ์.
ํจ์ฌ ๊น๋ํ๊ณ ๊ด๋ฆฌํ๊ธฐ ํธํ๊ฑฐ๋ ์ ใ
ใ
# config/services.yaml
services:
# ๊ธฐ๋ณธ ์ค์
_defaults:
autowire: true # ์๋ ์์ด์ด๋ง ํ์ฑํ
autoconfigure: true # ์๋ ์ค์ ํ์ฑํ
public: false # ๊ธฐ๋ณธ์ ์ผ๋ก private ์๋น์ค
# ๋ค์์คํ์ด์ค ์ ์ฒด ์๋ ๋ฑ๋ก
App\:
resource: '../src/'
exclude:
- '../src/DependencyInjection/'
- '../src/Entity/'
- '../src/Kernel.php'
# ๊ฐ๋ณ ์๋น์ค ์ค์
App\Service\UserService:
arguments:
$db: '@App\Repository\UserRepository'
$mailer: '@App\Service\MailerService'
tags:
- { name: 'app.service' }
# ํ๋ผ๋ฏธํฐ ์ฌ์ฉ
App\Service\SmtpMailer:
arguments:
$host: '%mailer.host%'
$port: '%mailer.port%'
parameters:
mailer.host: 'smtp.example.com'
mailer.port: 587
๐ค ํ์ ํํธ ๋ณด๊ณ ์ปจํ ์ด๋๊ฐ ์์์ ๋ง๋ ์๋น์ค ์ฃผ์ ํด์ค! ์๋ฅผ ๋ค์ด ์์ฑ์์ DatabaseInterface $db ์์ผ๋ฉด ์ปจํ ์ด๋๊ฐ DatabaseInterface ๊ตฌํ์ฒด ์ฐพ์์ ์๋์ผ๋ก ๋ฃ์ด์ค. ์ง์ง ํธํจ ใทใท
// PHP 8.1+ ์์ฑ์ ํ๋กํผํฐ ํ๋ก๋ชจ์
๊ณผ ํจ๊ป ์ฌ์ฉ
class OrderService {
public function __construct(
private UserRepository $userRepository, // ์๋ ์ฃผ์
!
private ProductRepository $productRepository, // ์๋ ์ฃผ์
!
private MailerInterface $mailer, // ์๋ ์ฃผ์
!
private LoggerInterface $logger // ์๋ ์ฃผ์
!
) {}
public function createOrder(int $userId, array $items): Order {
$user = $this->userRepository->find($userId);
// ... ์ฃผ๋ฌธ ์์ฑ ๋ก์ง
$this->mailer->send(new OrderConfirmationEmail($user));
$this->logger->info('Order created', ['user_id' => $userId]);
return $order;
}
}
// services.yaml์ autowire: true ์ค์ ๋ง ํด๋๋ฉด
// ์ปจํ
์ด๋๊ฐ ํ์
ํํธ ๋ณด๊ณ ์์์ ๋ค ์ฃผ์
ํด์ค! ๐
Symfony DI ์ปจํ
์ด๋์ ์ง์ง ๊ฐ๋ ฅํ ๊ธฐ๋ฅ ์ค ํ๋๊ฐ ๋ฐ๋ก ์๋น์ค ํ๊ทธ์์.
ํน์ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ ์๋น์ค๋ค์ ์๋์ผ๋ก ์์งํด์ ์ฒ๋ฆฌํ ์ ์์ด์. ์ด๊ฑฐ ์๋ฉด ์ง์ง ๋ ๋ฒจ์
๋จ ในใ
๐ฅ
// 1. ์ธํฐํ์ด์ค ์ ์
interface PaymentGatewayInterface {
public function getName(): string;
public function processPayment(float $amount): bool;
}
// 2. ๊ตฌํ์ฒด๋ค
class StripeGateway implements PaymentGatewayInterface {
public function getName(): string { return 'stripe'; }
public function processPayment(float $amount): bool {
// Stripe API ํธ์ถ
return true;
}
}
class PaypalGateway implements PaymentGatewayInterface {
public function getName(): string { return 'paypal'; }
public function processPayment(float $amount): bool {
// PayPal API ํธ์ถ
return true;
}
}
// 3. ์์ง๊ธฐ ์๋น์ค
class PaymentGatewayRegistry {
private array $gateways = [];
public function addGateway(PaymentGatewayInterface $gateway): void {
$this->gateways[$gateway->getName()] = $gateway;
}
public function getGateway(string $name): PaymentGatewayInterface {
return $this->gateways[$name]
?? throw new \InvalidArgumentException("Gateway '$name' not found");
}
}
# services.yaml - ํ๊ทธ ์ค์
services:
App\Payment\StripeGateway:
tags:
- { name: 'app.payment_gateway' }
App\Payment\PaypalGateway:
tags:
- { name: 'app.payment_gateway' }
App\Payment\PaymentGatewayRegistry:
# ํ๊ทธ๋ ์๋น์ค๋ค์ ์๋์ผ๋ก ์ฃผ์
!
// 4. ์ปดํ์ผ๋ฌ ํจ์ค - ํ๊ทธ๋ ์๋น์ค ์๋ ์์ง
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
class PaymentGatewayCompilerPass implements CompilerPassInterface {
public function process(ContainerBuilder $container): void {
if (!$container->has(PaymentGatewayRegistry::class)) {
return;
}
$registryDef = $container->findDefinition(PaymentGatewayRegistry::class);
// 'app.payment_gateway' ํ๊ทธ๊ฐ ๋ถ์ ๋ชจ๋ ์๋น์ค ์ฐพ๊ธฐ
$taggedServices = $container->findTaggedServiceIds('app.payment_gateway');
foreach ($taggedServices as $id => $tags) {
// ๋ ์ง์คํธ๋ฆฌ์ ์๋์ผ๋ก ์ถ๊ฐ
$registryDef->addMethodCall('addGateway', [new Reference($id)]);
}
}
}
// Kernel ๋๋ Bundle์ ๋ฑ๋ก
class AppKernel extends Kernel {
protected function build(ContainerBuilder $container): void {
$container->addCompilerPass(new PaymentGatewayCompilerPass());
}
}
Symfony 6.x๋ถํฐ๋ PHP 8 Attribute๋ฅผ ํ์ฉํด์ ํ๊ทธ๋ฅผ ๋ ๊ฐ๋จํ๊ฒ ์ค์ ํ ์ ์์ด์.
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
#[AutoconfigureTag('app.payment_gateway')]
class StripeGateway implements PaymentGatewayInterface {
// ...
}
// ๋๋ AsTaggedItem ์ฌ์ฉ
use Symfony\Component\DependencyInjection\Attribute\AsTaggedItem;
#[AsTaggedItem('app.payment_gateway', priority: 10)]
class StripeGateway implements PaymentGatewayInterface {
// ...
}
์ค๋ฌด์์๋ ๊ฐ๋ฐ(dev), ํ
์คํธ(test), ์ด์(prod) ํ๊ฒฝ๋ง๋ค ๋ค๋ฅธ ์ค์ ์ด ํ์ํ์ฃ .
Symfony๋ ์ด๊ฑธ ์ ๋ง ์ฐ์ํ๊ฒ ์ฒ๋ฆฌํด์ ๐
config/
โโโ services.yaml # ๊ณตํต ์๋น์ค ์ค์
โโโ services_dev.yaml # ๊ฐ๋ฐ ํ๊ฒฝ ์ ์ฉ
โโโ services_test.yaml # ํ
์คํธ ํ๊ฒฝ ์ ์ฉ
โโโ services_prod.yaml # ์ด์ ํ๊ฒฝ ์ ์ฉ
โโโ packages/
โ โโโ framework.yaml
โ โโโ doctrine.yaml
โ โโโ dev/
โ โโโ web_profiler.yaml # ๊ฐ๋ฐ ํ๊ฒฝ์์๋ง ๋ก๋
โโโ routes/
โโโ annotations.yaml
โโโ dev/
โโโ web_profiler.yaml
# config/services.yaml - ๊ณตํต ์ค์
parameters:
app.name: 'My Application'
app.version: '1.0.0'
services:
App\Service\UserService:
arguments:
$appName: '%app.name%' # ํ๋ผ๋ฏธํฐ ์ฐธ์กฐ
---
# config/services_dev.yaml - ๊ฐ๋ฐ ํ๊ฒฝ
parameters:
app.debug: true
services:
# ๊ฐ๋ฐ ํ๊ฒฝ์์๋ง ์ฌ์ฉํ ์๋น์ค
App\Service\DebugMailer:
decorates: App\Service\MailerService # ๋ฐ์ฝ๋ ์ดํฐ ํจํด!
---
# config/services_prod.yaml - ์ด์ ํ๊ฒฝ
parameters:
app.debug: false
# .env ํ์ผ
DATABASE_URL="mysql://user:password@localhost:3306/mydb"
MAILER_DSN="smtp://user:pass@smtp.example.com:587"
APP_SECRET="your-secret-key-here"
# config/services.yaml์์ ํ๊ฒฝ ๋ณ์ ์ฌ์ฉ
parameters:
database_url: '%env(DATABASE_URL)%'
services:
App\Repository\DatabaseConnection:
arguments:
$dsn: '%env(DATABASE_URL)%'
# ํ๊ฒฝ ๋ณ์ ํ๋ก์ธ์ ์ฌ์ฉ
$port: '%env(int:DATABASE_PORT)%' # ์ ์๋ก ๋ณํ
$debug: '%env(bool:APP_DEBUG)%' # ๋ถ๋ฆฌ์ธ์ผ๋ก ๋ณํ
env(string:VAR) ๋ฌธ์์ด (๊ธฐ๋ณธ๊ฐ)
env(int:VAR) ์ ์ ๋ณํ
env(float:VAR) ์ค์ ๋ณํ
env(bool:VAR) ๋ถ๋ฆฌ์ธ ๋ณํ
env(json:VAR) JSON ํ์ฑ
env(base64:VAR) Base64 ๋์ฝ๋ฉ
env(resolve:VAR) ๋ค๋ฅธ ํ๋ผ๋ฏธํฐ ์ฐธ์กฐ ํด๊ฒฐ
Symfony DI ์ปจํ
์ด๋์ ๋ ๋ค๋ฅธ ํฌ๋ฌ ๊ธฐ๋ฅ! ๋ฐ๋ก ์๋น์ค ๋ฐ์ฝ๋ ์ด์
์ด์์.
๊ธฐ์กด ์๋น์ค๋ฅผ ์์ ํ์ง ์๊ณ ๊ธฐ๋ฅ์ ํ์ฅํ ์ ์์ด์. ๊ฐ๋ฐฉ-ํ์ ์์น(OCP) ์๋ฒฝ ๊ตฌํ ใทใท
// ์๋ณธ ์๋น์ค
class UserRepository {
public function find(int $id): ?User {
// DB์์ ์ฌ์ฉ์ ์กฐํ
return $this->db->findOne('users', $id);
}
}
// ์บ์ฑ ๋ฐ์ฝ๋ ์ดํฐ
class CachedUserRepository {
public function __construct(
private UserRepository $inner, // ์๋ณธ ์๋น์ค ์ฃผ์
private CacheInterface $cache
) {}
public function find(int $id): ?User {
$cacheKey = "user_{$id}";
// ์บ์์์ ๋จผ์ ์ฐพ๊ธฐ
if ($this->cache->has($cacheKey)) {
return $this->cache->get($cacheKey);
}
// ์์ผ๋ฉด ์๋ณธ์์ ๊ฐ์ ธ์์ ์บ์์ ์ ์ฅ
$user = $this->inner->find($id);
$this->cache->set($cacheKey, $user, 3600);
return $user;
}
}
# services.yaml - ๋ฐ์ฝ๋ ์ดํฐ ์ค์
services:
App\Repository\UserRepository: ~ # ์๋ณธ ์๋น์ค
App\Repository\CachedUserRepository:
decorates: App\Repository\UserRepository # ๋ฐ์ฝ๋ ์ด์
!
arguments:
$inner: '@.inner' # ์๋ณธ ์๋น์ค ์๋ ์ฐธ์กฐ
๐ค ์๋ณธ ์ฝ๋ ๊ฑด๋๋ฆฌ์ง ์๊ณ ์บ์ฑ, ๋ก๊น , ํธ๋์ญ์ ๊ฐ์ ๊ธฐ๋ฅ ์ถ๊ฐํ ์ ์์ด! ๊ทธ๋ฆฌ๊ณ ํ ์คํธ ํ๊ฒฝ์์๋ ๋ฐ์ฝ๋ ์ดํฐ ๋นผ๊ณ ์๋ณธ๋ง ์ธ ์๋ ์๊ณ . ์ง์ง ์ ์ฐํจ ในใ ๐ฅ
Symfony ์ปดํฌ๋ํธ์ DI ์ปจํ
์ด๋๋ฅผ ํ์ฉํ ์ค์ ์ํคํ
์ฒ๋ฅผ ์ดํด๋ณผ๊ฒ์.
์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์ ๋ง๋ ๋ค๊ณ ๊ฐ์ ํ๊ณ ์ค๊ณํด๋ณผ๊ฒ์! ๐ฏ
src/
โโโ Controller/ # ํ๋ ์ ํ
์ด์
๋ ์ด์ด
โ โโโ UserController.php
โ โโโ OrderController.php
โ
โโโ Application/ # ์ ํ๋ฆฌ์ผ์ด์
๋ ์ด์ด
โ โโโ Command/
โ โ โโโ CreateUserCommand.php
โ โ โโโ CreateUserHandler.php
โ โโโ Query/
โ โโโ GetUserQuery.php
โ โโโ GetUserHandler.php
โ
โโโ Domain/ # ๋๋ฉ์ธ ๋ ์ด์ด
โ โโโ Entity/
โ โ โโโ User.php
โ โโโ Repository/
โ โ โโโ UserRepositoryInterface.php # ์ธํฐํ์ด์ค๋ง!
โ โโโ Service/
โ โโโ UserDomainService.php
โ
โโโ Infrastructure/ # ์ธํ๋ผ ๋ ์ด์ด
โโโ Repository/
โ โโโ DoctrineUserRepository.php # ๊ตฌํ์ฒด
โโโ Mailer/
โ โโโ SymfonyMailer.php
โโโ Cache/
โโโ RedisCache.php
// Command - ์ฌ์ฉ์ ์์ฑ ๋ช
๋ น
class CreateUserCommand {
public function __construct(
public readonly string $email,
public readonly string $name,
public readonly string $password
) {}
}
// Handler - ๋ช
๋ น ์ฒ๋ฆฌ
class CreateUserHandler {
public function __construct(
private UserRepositoryInterface $userRepository,
private PasswordHasherInterface $passwordHasher,
private EventDispatcherInterface $eventDispatcher,
private LoggerInterface $logger
) {}
public function __invoke(CreateUserCommand $command): User {
// ์ด๋ฉ์ผ ์ค๋ณต ํ์ธ
if ($this->userRepository->existsByEmail($command->email)) {
throw new UserAlreadyExistsException($command->email);
}
// ์ฌ์ฉ์ ์์ฑ
$user = new User(
email: $command->email,
name: $command->name,
passwordHash: $this->passwordHasher->hash($command->password)
);
$this->userRepository->save($user);
// ์ด๋ฒคํธ ๋ฐํ
$this->eventDispatcher->dispatch(new UserCreatedEvent($user));
$this->logger->info('User created', ['email' => $command->email]);
return $user;
}
}
# services.yaml - ์๋ ์์ด์ด๋ง์ผ๋ก ๊ฐ๋จํ๊ฒ!
services:
_defaults:
autowire: true
autoconfigure: true
App\:
resource: '../src/'
# ์ธํฐํ์ด์ค โ ๊ตฌํ์ฒด ๋ฐ์ธ๋ฉ
App\Domain\Repository\UserRepositoryInterface:
alias: App\Infrastructure\Repository\DoctrineUserRepository
App\Domain\Service\PasswordHasherInterface:
alias: App\Infrastructure\Security\BcryptPasswordHasher
๐ค ๋ง์! Controller์์ ๊ทธ๋ฅ ํ์ ํํธ๋ก ๋ฐ์ผ๋ฉด ์ปจํ ์ด๋๊ฐ ์์์ ๋ค ๋ง๋ค์ด์ ์ฃผ์ ํด์ค. ์ง์ง ๋ง๋ฒ ๊ฐ์ ใ ใ ใ ๊ทธ๋ฆฌ๊ณ ๋์ค์ DB ๋ฐ๊ฟ๋ ์ธํฐํ์ด์ค ๊ตฌํ์ฒด๋ง ๋ฐ๊พธ๋ฉด ๋๋๊น ์ ์ง๋ณด์๋ ์ฌ์!
DI ์ปจํ
์ด๋๊ฐ ํธ๋ฆฌํ๊ธด ํ๋ฐ, ์๋ชป ์ฐ๋ฉด ์ฑ๋ฅ ์ด์๊ฐ ์๊ธธ ์ ์์ด์.
Symfony๋ ์ด ๋ฌธ์ ๋ฅผ ์ด๋ป๊ฒ ํด๊ฒฐํ๋์ง ์์๋ณผ๊ฒ์!
// Symfony๋ ์ปจํ
์ด๋๋ฅผ ์ปดํ์ผํด์ ์ต์ ํ๋ PHP ํ์ผ๋ก ์ ์ฅ
// var/cache/prod/App_KernelProdContainer.php ๊ฐ์ ํ์ผ์ด ์์ฑ๋จ
// ์ปดํ์ผ๋ ์ปจํ
์ด๋๋ ์ด๋ฐ ํํ
class App_KernelProdContainer extends Container {
// ๋ชจ๋ ์๋น์ค ์ ์๊ฐ ์ต์ ํ๋ PHP ์ฝ๋๋ก ๋ณํ๋จ
protected function getUserService(): UserService {
return $this->services['App\\Service\\UserService']
??= new UserService(
$this->getDoctrineUserRepositoryService(),
$this->getSymfonyMailerService()
);
}
}
// ์ด์ ํ๊ฒฝ์์๋ ์ด ์บ์๋ ์ปจํ
์ด๋๋ฅผ ์ฌ์ฉ
// โ ๋งค ์์ฒญ๋ง๋ค YAML ํ์ฑ ์์, ์ฆ์ ์ฌ์ฉ ๊ฐ๋ฅ!
# services.yaml - ๋ฌด๊ฑฐ์ด ์๋น์ค๋ lazy ์ค์
services:
App\Service\HeavyReportGenerator:
lazy: true # ์ค์ ๋ก ์ฌ์ฉ๋ ๋๋ง ์ธ์คํด์ค ์์ฑ
App\Service\ExternalApiClient:
lazy: true
// PHP 8.4+ ์์๋ Lazy Ghost ๊ฐ์ฒด ์ง์
// ์ค์ ๋ฉ์๋ ํธ์ถ ์ ๊น์ง ์ด๊ธฐํ ์ ๋จ
use Symfony\Component\DependencyInjection\Attribute\Lazy;
class OrderController {
public function __construct(
#[Lazy] private HeavyReportGenerator $reportGenerator,
// ์ด ์๋น์ค๋ ์ค์ ๋ก ์ฌ์ฉํ ๋๋ง ์ด๊ธฐํ๋จ!
) {}
public function index(): Response {
// reportGenerator๋ ์ฌ๊ธฐ์ ์ด๊ธฐํ ์ ๋จ
return new Response('Hello');
}
public function generateReport(): Response {
// ์ฌ๊ธฐ์ ์ฒ์ ์ฌ์ฉ๋ ๋ ์ด๊ธฐํ๋จ
$report = $this->reportGenerator->generate();
return new Response($report);
}
}
โ ์ด์ ํ๊ฒฝ์์
APP_ENV=prod ์ค์ โ
php bin/console cache:warmup์ผ๋ก ์ปจํ
์ด๋ ์ฌ์ ์ปดํ์ผโ ๋ฌด๊ฑฐ์ด ์๋น์ค์
lazy: true ์ค์ โ ๋ถํ์ํ ์๋น์ค ์๋ ๋ฑ๋ก ์ ์ธ (
exclude ์ค์ )โ OPcache ํ์ฑํ๋ก ์ปดํ์ผ๋ ์ปจํ ์ด๋ ์บ์ฑ
โ ์๋น์ค๋ฅผ
public: false๋ก ์ค์ ํด ์ต์ ํ ํ์ฉ
DI ์ปจํ
์ด๋์ ๊ฐ์ฅ ํฐ ์ฅ์ ์ค ํ๋๊ฐ ๋ฐ๋ก ํ
์คํธ ์ฉ์ด์ฑ์ด์์.
์์กด์ฑ์ ์ธ๋ถ์์ ์ฃผ์
ํ๋๊น ํ
์คํธ ์ Mock ๊ฐ์ฒด๋ก ์ฝ๊ฒ ๊ต์ฒดํ ์ ์๊ฑฐ๋ ์!
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\MockObject\MockObject;
class CreateUserHandlerTest extends TestCase {
private UserRepositoryInterface&MockObject $userRepository;
private PasswordHasherInterface&MockObject $passwordHasher;
private EventDispatcherInterface&MockObject $eventDispatcher;
private CreateUserHandler $handler;
protected function setUp(): void {
// Mock ๊ฐ์ฒด ์์ฑ
$this->userRepository = $this->createMock(UserRepositoryInterface::class);
$this->passwordHasher = $this->createMock(PasswordHasherInterface::class);
$this->eventDispatcher = $this->createMock(EventDispatcherInterface::class);
// ์ง์ ์์กด์ฑ ์ฃผ์
! (์ปจํ
์ด๋ ์์ด๋ ํ
์คํธ ๊ฐ๋ฅ)
$this->handler = new CreateUserHandler(
$this->userRepository,
$this->passwordHasher,
$this->eventDispatcher,
new NullLogger() // ์ค์ ๋ก๊ฑฐ ๋์ Null ๋ก๊ฑฐ
);
}
public function testCreateUserSuccessfully(): void {
// Given
$command = new CreateUserCommand('test@example.com', 'Test User', 'password123');
$this->userRepository
->expects($this->once())
->method('existsByEmail')
->with('test@example.com')
->willReturn(false); // ์ด๋ฉ์ผ ์ค๋ณต ์์
$this->passwordHasher
->expects($this->once())
->method('hash')
->willReturn('hashed_password');
$this->userRepository
->expects($this->once())
->method('save');
$this->eventDispatcher
->expects($this->once())
->method('dispatch')
->with($this->isInstanceOf(UserCreatedEvent::class));
// When
$user = ($this->handler)($command);
// Then
$this->assertEquals('test@example.com', $user->getEmail());
$this->assertEquals('Test User', $user->getName());
}
public function testThrowsExceptionForDuplicateEmail(): void {
$command = new CreateUserCommand('existing@example.com', 'User', 'pass');
$this->userRepository
->method('existsByEmail')
->willReturn(true); // ์ด๋ฉ์ผ ์ค๋ณต!
$this->expectException(UserAlreadyExistsException::class);
($this->handler)($command);
}
}
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
class UserServiceIntegrationTest extends KernelTestCase {
private UserService $userService;
protected function setUp(): void {
// Symfony ํ
์คํธ ์ปค๋ ๋ถํ
self::bootKernel(['environment' => 'test']);
// ์ปจํ
์ด๋์์ ์๋น์ค ๊ฐ์ ธ์ค๊ธฐ
$this->userService = static::getContainer()->get(UserService::class);
}
public function testFindUser(): void {
// ์ค์ ํ
์คํธ DB ์ฌ์ฉ (test ํ๊ฒฝ)
$user = $this->userService->findUser(1);
$this->assertNotNull($user);
}
}
๐ค ใ ใ ใ ๊ทธ๋์ test ํ๊ฒฝ์์๋ services_test.yaml์์ Mailer๋ฅผ NullMailer๋ก ๊ต์ฒดํด! ์ปจํ ์ด๋๊ฐ ํ๊ฒฝ๋ณ๋ก ๋ค๋ฅธ ๊ตฌํ์ฒด ์ฃผ์ ํด์ฃผ๋๊น ์ง์ง ํธํจ. ์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ ๊ฐ๋ฐํ ๋ ์ด๋ฐ ์ค์ ํ์์ ในใ
# config/services_test.yaml - ํ
์คํธ ํ๊ฒฝ ์ ์ฉ
services:
# ์ค์ ๋ฉ์ผ๋ฌ ๋์ Null ๋ฉ์ผ๋ฌ ์ฌ์ฉ
App\Service\MailerInterface:
alias: App\Service\NullMailer
# ์ค์ ๊ฒฐ์ ๊ฒ์ดํธ์จ์ด ๋์ Mock ์ฌ์ฉ
App\Payment\PaymentGatewayInterface:
alias: App\Payment\MockPaymentGateway
# ์ธ๋ถ API ํด๋ผ์ด์ธํธ Mock
App\Api\ExternalApiClient:
alias: App\Api\MockExternalApiClient
๐ค ใ ใ ์ง์ง ๋ง์ ใ ใ ใ ๋ํ์ ์ธ ์ํฐํจํด๋ค ์๋ ค์ค๊ฒ!
// โ ๋์ ์ - ์๋น์ค ๋ก์ผ์ดํฐ ํจํด (์ํฐํจํด!)
class UserController {
public function __construct(
private ContainerInterface $container // ์ปจํ
์ด๋ ์์ฒด๋ฅผ ์ฃผ์
) {}
public function createUser(): Response {
// ์ปจํ
์ด๋์์ ์ง์ ๊บผ๋ด ์ - ์์กด์ฑ์ด ์จ๊ฒจ์ง!
$userService = $this->container->get(UserService::class);
$mailer = $this->container->get(MailerInterface::class);
// ...
}
}
// โ
์ข์ ์ - ํ์ํ ์๋น์ค๋ง ์ง์ ์ฃผ์
class UserController {
public function __construct(
private UserService $userService,
private MailerInterface $mailer
) {}
// ์์กด์ฑ์ด ๋ช
ํํ๊ฒ ๋๋ฌ๋จ!
}
// โ ๋์ ์ - ์์ฑ์์ ์์กด์ฑ์ด ๋๋ฌด ๋ง์ (๋จ์ผ ์ฑ
์ ์์น ์๋ฐ ์ ํธ!)
class GodService {
public function __construct(
private UserRepository $userRepo,
private OrderRepository $orderRepo,
private ProductRepository $productRepo,
private MailerInterface $mailer,
private CacheInterface $cache,
private LoggerInterface $logger,
private EventDispatcherInterface $dispatcher,
private PaymentGateway $payment,
private ShippingService $shipping,
private NotificationService $notification
// ์ด๋ ๊ฒ ๋ง์ผ๋ฉด ํด๋์ค ๋ถ๋ฆฌ ์ ํธ!
) {}
}
// โ
์ข์ ์ - ์ฑ
์ ๋ถ๋ฆฌ
class OrderService {
public function __construct(
private OrderRepository $orderRepo,
private PaymentService $paymentService, // ๊ฒฐ์ ๊ด๋ จ ๋ฌถ์
private ShippingService $shippingService // ๋ฐฐ์ก ๊ด๋ จ ๋ฌถ์
) {}
}
1. ์ธํฐํ์ด์ค์ ์์กดํ๋ผ
๊ตฌ์ฒด ํด๋์ค ๋์ ์ธํฐํ์ด์ค์ ์์กดํด์ ๊ต์ฒด ๊ฐ๋ฅ์ฑ ํ๋ณด
2. ์์ฑ์ ์ฃผ์ ์ ๊ธฐ๋ณธ์ผ๋ก
Setter ์ฃผ์ ๋ณด๋ค ์์ฑ์ ์ฃผ์ ์ด ๋ถ๋ณ์ฑ ๋ณด์ฅ์ ์ ๋ฆฌ
3. ์๋น์ค๋ ๊ธฐ๋ณธ์ ์ผ๋ก private
public: false๊ฐ ๊ธฐ๋ณธ๊ฐ โ ์ปจํ
์ด๋ ์ต์ ํ์ ๋์4. autowire + autoconfigure ํ์ฉ
๋ฐ๋ณต์ ์ธ ์ค์ ์ค์ด๊ณ ์ปจ๋ฒค์ ๊ธฐ๋ฐ ์๋ํ
5. ํ๊ฒฝ๋ณ ์ค์ ๋ถ๋ฆฌ
dev/test/prod ํ๊ฒฝ๋ง๋ค ์ ์ ํ ๊ตฌํ์ฒด ์ฌ์ฉ
6. ์ปดํ์ผ๋ฌ ํจ์ค๋ก ํ์ฅ
ํ๊ทธ ๊ธฐ๋ฐ ์๋น์ค ์์ง์ผ๋ก ํ๋ฌ๊ทธ์ธ ์ํคํ ์ฒ ๊ตฌํ
# ๋ฑ๋ก๋ ์๋น์ค ๋ชฉ๋ก ํ์ธ
php bin/console debug:container
# ํน์ ์๋น์ค ์์ธ ์ ๋ณด
php bin/console debug:container App\Service\UserService
# ์๋ ์์ด์ด๋ง ๊ฐ๋ฅํ ํ์
๋ชฉ๋ก
php bin/console debug:autowiring
# ํน์ ํ์
์ผ๋ก ํํฐ๋ง
php bin/console debug:autowiring Logger
# ์ด๋ฒคํธ ๋ฆฌ์ค๋ ๋ชฉ๋ก
php bin/console debug:event-dispatcher
# ๋ผ์ฐํ
์ ๋ณด
php bin/console debug:router
Symfony 6.x๋ถํฐ๋ PHP 8์ Attribute๋ฅผ ์ ๊ทน ํ์ฉํด์
YAML ์ค์ ์์ด๋ ์๋น์ค๋ฅผ ์ค์ ํ ์ ์์ด์. ์ง์ง ๊ฐํธํจ ใทใท ๐ฅ
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\DependencyInjection\Attribute\TaggedIterator;
use Symfony\Component\DependencyInjection\Attribute\When;
class NotificationService {
public function __construct(
// ํ๊ฒฝ ๋ณ์ ์ง์ ์ฃผ์
#[Autowire('%env(NOTIFICATION_API_KEY)%')]
private string $apiKey,
// ํน์ ์๋น์ค ๋ช
์์ ์ฃผ์
#[Autowire(service: 'app.primary_mailer')]
private MailerInterface $mailer,
// ํ๊ทธ๋ ์๋น์ค๋ค ์ดํฐ๋ ์ดํฐ๋ก ์ฃผ์
#[TaggedIterator('app.notification_channel')]
private iterable $channels
) {}
}
// ํน์ ํ๊ฒฝ์์๋ง ํ์ฑํ
#[When(env: 'dev')]
class DebugNotificationService extends NotificationService {
// ๊ฐ๋ฐ ํ๊ฒฝ์์๋ง ์ฌ์ฉ๋๋ ๊ตฌํ์ฒด
}
// ์๋น์ค์ ํ๊ทธ ์๋ ์ถ๊ฐ
use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag;
#[AutoconfigureTag('app.notification_channel', ['priority' => 10])]
class EmailNotificationChannel implements NotificationChannelInterface {
public function send(string $message): void {
// ์ด๋ฉ์ผ ๋ฐ์ก
}
}
#[AutoconfigureTag('app.notification_channel', ['priority' => 5])]
class SmsNotificationChannel implements NotificationChannelInterface {
public function send(string $message): void {
// SMS ๋ฐ์ก
}
}
#[AutowireDecorated] ๋ฐ์ฝ๋ ์ดํฐ ์๋ ์์ด์ด๋ง
#[AsAlias] ์๋น์ค ๋ณ์นญ ์ค์
#[AsDecorator] ๋ฐ์ฝ๋ ์ดํฐ ์ ์ธ
#[Exclude] ์๋ ๋ฑ๋ก์์ ์ ์ธ
#[Lazy] ์ง์ฐ ๋ก๋ฉ ์ค์
#[Target] ๋์ผ ํ์ ์ฌ๋ฌ ์๋น์ค ๊ตฌ๋ถ
Symfony ์ปดํฌ๋ํธ ๊ธฐ๋ฐ ์ํคํ
์ฒ์ DI ์ปจํ
์ด๋๋ ์ฒ์์๋ ๋ณต์กํด ๋ณด์ผ ์ ์์ด์.
๊ทผ๋ฐ ํ ๋ฒ ์ ๋๋ก ์ดํดํ๊ณ ๋๋ฉด ์ฝ๋ ํ์ง, ์ ์ง๋ณด์์ฑ, ํ
์คํธ ์ฉ์ด์ฑ์ด ์์ฒญ๋๊ฒ ์ฌ๋ผ๊ฐ์.
ํนํ ํ ํ๋ก์ ํธ๋ ์ฅ๊ธฐ ์ด์ ์๋น์ค์์๋ ์ด๋ฐ ์ํคํ
์ฒ๊ฐ ์ง์ง ๋น์ ๋ฐํด์.
์ฌ๋ฅ๋ท์ฒ๋ผ ๋ค์ํ ๊ธฐ๋ฅ์ด ๊ณ์ ์ถ๊ฐ๋๋ ํ๋ซํผ์ ๊ฐ๋ฐํ ๋๋ Symfony์ ์ปดํฌ๋ํธ ๊ธฐ๋ฐ ์ ๊ทผ๋ฒ์ด ํฐ ๋์์ด ๋ฉ๋๋ค ๐ช
์ฒ์์๋ ์์กด์ฑ ์ฃผ์
๊ฐ๋
โ ๊ธฐ๋ณธ ์ปจํ
์ด๋ ์ฌ์ฉ โ ์๋ ์์ด์ด๋ง โ ๊ณ ๊ธ ๊ธฐ๋ฅ ์์๋ก ์ฐจ๊ทผ์ฐจ๊ทผ ์ตํ๊ฐ์ธ์.
์ด๋ ์๊ฐ "์ ์ด๋์ Symfony๊ฐ PHP ์ํ๊ณ์ ์ธํ๋ผ๊ตฌ๋!" ํ๋ ์๊ฐ์ด ์ฌ ๊ฑฐ์์ ใ
ใ
ใ
๐
๊ณต์ ๋ฌธ์ โ symfony.com/doc/current/service_container.html
Symfony Cast โ symfonycasts.com (์์ ๊ฐ์, ์ง์ง ์ข์)
PHP-DI โ php-di.org (Symfony ์ธ ๋ค๋ฅธ DI ์ปจํ ์ด๋ ๋น๊ต ํ์ต)
PSR-11 โ Container Interface ํ์ค ์คํ ์ดํด
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.