# Symfony Bağımlılık Enjeksiyonu: Servis Konteyneri, Autowiring ve Etiketler 2026 > Symfony bağımlılık enjeksiyonuna derinlemesine bakış: servis konteyneri, autowiring, #[Autowire] özniteliği, arayüz bağlama, #[AutowireIterator] ile etiketlenmiş servisler, compiler pass'ler ve Symfony 7.4 ile 8.0'da tembel servisler. - Published: 2026-07-06 - Updated: 2026-07-07 - Author: SharpSkill - Tags: symfony, dependency injection, service container, autowiring, php, di - Reading time: 11 min --- Bağımlılık enjeksiyonu her Symfony uygulamasının belkemiğidir: servis konteyneri nesneleri örnekler, yapılandırır ve birbirine bağlar; böylece sınıflar ihtiyaç duydukları şeyleri kendileri oluşturmak yerine yalnızca beyan eder. Symfony 7.4 ve 8.0'da autowiring, PHP öznitelikleri ve etiketlenmiş servisler, açık yapılandırmayı neredeyse sıfıra indirirken konteyneri derleme zamanında tamamen çözülmüş ve öngörülebilir tutar. Bu çözümlemenin nasıl işlediğini anlamak, konteynerle boğuşan geliştiricileri, onun işini yapmasına izin verenlerden ayırır. > **Symfony'de bağımlılık enjeksiyonu nedir?** > > Symfony'de bağımlılık enjeksiyonu, servis konteynerinin bir nesnenin bağımlılıklarını, nesnenin bunları kendisinin oluşturmasına izin vermek yerine yapıcı metot (constructor) üzerinden geçirdiği bir kalıptır. Autowiring, tür ipucu (type hint) verilmiş her argümanı eşleşen bir servise otomatik olarak çözümler; böylece çoğu sınıf hiçbir manuel yapılandırmaya ihtiyaç duymaz. ## Symfony Servis Konteyneri Bağımlılıkları Nasıl Çözer Servis konteyneri, uygulamadaki her servisi nasıl oluşturacağını bilen, derlenmiş bir PHP sınıfıdır. Konteyner derleme aşamasında Symfony sınıf tanımlarını tarar, yapıcı metot imzalarını okur ve önbelleğe alınmış bir fabrika üretir. Çalışma zamanında bir servis talep etmek, tembel (lazy) biçimde oluşturulan, paylaşılan bir örnek döndürür. Bağlama işlemi derleme zamanında gerçekleştiği için yanlış yapılandırılmış bir bağımlılık, bir istek üretime ulaştığında değil, önbellek oluşturulurken hata verir. Servis, basitçe bir görevi yerine getiren ve konteyner tarafından yönetilen bir sınıftır. Varsayılan `config/services.yaml` dosyası, `src/` altındaki her şeyi autowiring ve autoconfiguration etkin bir servis olarak kaydeder; sıradan bir sınıfın ek bir kuruluma gerek kalmadan çalışmasının nedeni budur. ```yaml # config/services.yaml services: _defaults: autowire: true # inject arguments by type-hint autoconfigure: true # apply tags based on implemented interfaces App\: resource: '../src/' exclude: - '../src/Entity/' - '../src/Kernel.php' ``` Bu varsayılanlar yerindeyken bir sınıf, işbirlikçilerini yapıcı metodu üzerinden ister ve konteyner bunları sağlar. Fabrika yok, `new` yok, manuel argüman listesi yok. ```php // src/Notification/SlackNotifier.php namespace App\Notification; use Psr\Log\LoggerInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; final class SlackNotifier { // The container reads each type-hint and injects a matching service public function __construct( private readonly HttpClientInterface $httpClient, private readonly LoggerInterface $logger, ) {} public function send(string $channel, string $message): void { $this->httpClient->request('POST', 'https://slack.example/api/post', [ 'json' => ['channel' => $channel, 'text' => $message], ]); $this->logger->info('Slack message dispatched', ['channel' => $channel]); } } ``` Konteyner `SlackNotifier` örneğini bir kez oluşturur, paylaşılan HTTP istemcisini ve logger'ı enjekte eder ve bu örneği talep edildiği her yerde yeniden kullanır. Varsayılan olarak paylaşımlı olan bu davranış, konteyneri hem hızlı hem de bellek açısından verimli kılan şeydir. Tam model, PHP ekosisteminde paylaşılan [PSR-11 konteyner arayüzü](https://www.php-fig.org/psr/psr-11/) standardının üzerine kurulan resmi [Symfony servis konteyneri kılavuzunda](https://symfony.com/doc/current/service_container.html) belgelenmiştir. Her istekte taze bir örnek gerektiğinde, örneğin veri biriktiren durumlu (stateful) bir oluşturucu için paylaşım kapatılabilir. Bir tanım üzerinde `shared: false` ayarlamak, onu her enjekte edilişinde yeni bir nesne döndüren bir fabrikaya dönüştürür. Çoğu servis durumsuz işbirlikçiler olduğundan bu uygulamada nadirdir; ancak bir hata, aynı nesneyi beklenmedik biçimde değiştiren iki tüketiciye kadar izlendiğinde, bu varsayılanın var olduğunu ve nasıl geçersiz kılınacağını bilmek önem taşır. ## Symfony Autowiring: Tür İpuçları ve Autowire Özniteliği Symfony autowiring, yapıcı metot argümanlarını tür bildirimlerine göre çözer. Bir argümana tam olarak tek bir servise karşılık gelen bir sınıf veya arayüz türü ipucu verildiğinde, konteyner onu hiçbir yapılandırma olmadan enjekte eder. Autowiring yalnızca servis olmayan değerlerde işlevini yitirir: skaler değerler, ortam değişkenleri ve parametreler. `#[Autowire]` özniteliği bu boşluğu doğrudan argümanın üzerinde kapatarak bağlama işini onu kullanan kodun hemen yanında tutar. ```php // src/Service/PaymentGateway.php namespace App\Service; use Psr\Log\LoggerInterface; use Symfony\Component\DependencyInjection\Attribute\Autowire; final class PaymentGateway { public function __construct( // Inject a container parameter with the %...% syntax #[Autowire('%kernel.environment%')] private readonly string $environment, // Inject an environment variable, resolved at runtime #[Autowire(env: 'STRIPE_SECRET')] private readonly string $apiKey, // Bind a specific service when the type alone is ambiguous #[Autowire(service: 'monolog.logger.payment')] private readonly LoggerInterface $logger, ) {} } ``` Her argüman kendi kaynağını bildirir: bir parametre, bir ortam değişkeni veya adlandırılmış bir servis. Öznitelik ayrıca Expression Language değerleri için bir `expression:` argümanını da kabul eder; bu, bir bağımlılık statik bir tanımdan değil de çalışma zamanı hesaplamasından geldiğinde işe yarar. Bu meta verileri yapıcı metotta tutmak, okuyucunun her değerin tam olarak nereden geldiğini ayrı bir YAML dosyası açmadan görmesini sağlar. Öznitelik başvurusu [Symfony autowiring belgelerinde](https://symfony.com/doc/current/service_container/autowiring.html) yer alır. > **Somut sınıflara değil, arayüzlere tür ipucu verin** > > `S3Storage` gibi somut bir sınıfa autowiring uygulamak, her tüketiciyi o gerçeklemeye bağlar ve testlerde onu değiştirmeyi zorlaştırır. Bunun yerine arayüze tür ipucu vermek ve somut servise `#[AsAlias]` ya da `#[Autowire(service: ...)]` karar vermek gerekir. Servisleri elle almak için tüm konteyneri enjekte etmek, derleme zamanı kontrollerini boşa çıkarır ve tam olarak autowiring'in ortadan kaldırmak için var olduğu anti-kalıptır. ## Birden Fazla Gerçekleme Varken Arayüzleri Bağlama Bir arayüze karşı autowiring, iki sınıf onu gerçekleyene kadar sorunsuz çalışır. Bu noktada konteyner hangisini enjekte edeceğini tahmin edemez ve derleme zamanında bir belirsizlik hatası fırlatır. Bunu iki öznitelik çözer: `#[AsAlias]` bir gerçeklemeyi arayüz için varsayılan olarak işaretler, `#[Autowire(service: ...)]` ise tekil bir argümana belirli bir gerçeklemeyi sabitler. ```php // src/Storage/StorageInterface.php namespace App\Storage; interface StorageInterface { public function put(string $key, string $contents): void; } ``` ```php // src/Storage/S3Storage.php namespace App\Storage; use Symfony\Component\DependencyInjection\Attribute\AsAlias; // Becomes the default service returned for StorageInterface #[AsAlias(StorageInterface::class)] final class S3Storage implements StorageInterface { public function put(string $key, string $contents): void { /* upload to S3 */ } } ``` ```php // src/Service/BackupService.php namespace App\Service; use App\Storage\LocalStorage; use App\Storage\StorageInterface; use Symfony\Component\DependencyInjection\Attribute\Autowire; final class BackupService { public function __construct( // Resolves to the #[AsAlias] default (S3Storage) private readonly StorageInterface $primary, // Pins the concrete implementation explicitly by service id #[Autowire(service: LocalStorage::class)] private readonly StorageInterface $fallback, ) {} } ``` `#[Target]` özniteliği üçüncü bir seçenek sunar: bir gerçeklemeye autowiring takma adı üzerinden başvurarak argüman değişkeninin adını çözümlemeden ayırır. Bunlar arasındaki seçim niyete bağlıdır. Bir gerçekleme kod tabanı genelinde gerçekten varsayılan olduğunda `#[AsAlias]`, tekil bir tüketici varsayılan olmayan bir varyanta ihtiyaç duyduğunda ise `#[Autowire(service: ...)]` veya `#[Target]` tercih edilir. Bu kalıp üretim uygulamalarında sürekli ortaya çıkar ve [Symfony bağımlılık enjeksiyonu mülakat modülünün](/technologies/symfony/interview-questions/dependency-injection) gözde konularından biridir. ## Symfony Servis Etiketleri ve AutowireIterator Toplayıcısı Etiketler, Symfony'nin ilgili servisleri gruplandırma biçimidir; böylece başka bir servis hepsini birden tüketebilir. Bu, framework'ün her yerinde görülen strateji, sorumluluk zinciri ve eklenti kalıplarını besler: form tipi uzantıları, Twig uzantıları ve olay aboneleri hep etiket güdümlüdür. Elle etiketlemek yerine, bir arayüz üzerine yerleştirilen `#[AutoconfigureTag]`, konteynere onu gerçekleyen her sınıfı otomatik olarak etiketlemesini söyler. ```php // src/Export/ExporterInterface.php namespace App\Export; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; // Every class implementing this interface is tagged automatically #[AutoconfigureTag('app.exporter')] interface ExporterInterface { public function supports(string $format): bool; public function export(array $rows): string; } ``` Bireysel gerçeklemeler, koleksiyondaki konumlarını `#[AsTaggedItem]` ile denetler; bu öznitelik bir öncelik (yüksek olan önce çalışır) ve anahtarla erişim için isteğe bağlı bir dize dizini belirler. ```php // src/Export/CsvExporter.php namespace App\Export; use Symfony\Component\DependencyInjection\Attribute\AsTaggedItem; // Higher priority services appear earlier in the injected iterable #[AsTaggedItem(priority: 10)] final class CsvExporter implements ExporterInterface { public function supports(string $format): bool { return $format === 'csv'; } public function export(array $rows): string { return implode("\n", array_map(fn ($r) => implode(',', $r), $rows)); } } ``` Tüketen servis, `#[AutowireIterator]` kullanarak etiketlenmiş her dışa aktarıcıyı sıralı bir `iterable` içinde toplar. Ardından koleksiyonda ilerler ve görevi, istenen biçimi destekleyen ilk stratejiye devreder. ```php // src/Export/ExportManager.php namespace App\Export; use Symfony\Component\DependencyInjection\Attribute\AutowireIterator; final class ExportManager { // Collects all services tagged 'app.exporter', ordered by priority public function __construct( #[AutowireIterator('app.exporter')] private readonly iterable $exporters, ) {} public function export(string $format, array $rows): string { foreach ($this->exporters as $exporter) { if ($exporter->supports($format)) { return $exporter->export($rows); } } throw new \InvalidArgumentException("No exporter for format: $format"); } } ``` Koleksiyon büyük veya oluşturması pahalı olduğunda `#[AutowireLocator]` tembel alternatiftir: etiketlenmiş bir servisi yalnızca anahtarıyla gerçekten alındığında örnekleyen, PSR-11 uyumlu bir konteyner enjekte eder. Hevesli (eager) yineleme ile tembel arama arasındaki bu ayrım, bağlantı veya ağır durum tutan servisler için önemlidir. ## Autoconfiguration, Compiler Pass'ler ve Tembel Servisler Autoconfiguration, `#[AutoconfigureTag]` ve `#[AsTaggedItem]` gibi öznitelikleri okuyup derleme sırasında uygulayan mekanizmadır. `EventSubscriberInterface`'i gerçeklemenin, sıfır yapılandırmayla bir olay abonesini kaydetmeye yetmesinin nedeni budur. Özniteliklerin ifade edemediği dönüşümler için bir compiler pass, doğrudan konteyner yapımına bağlanır ve önbellek yazılmadan önce tanımları değiştirir. [GitHub'daki](https://github.com/symfony/dependency-injection) `DependencyInjection` bileşeninin kaynak kodu, framework'ün bu geçişlerin düzinelercesini kendi içinde nasıl kullandığını gösterir. Performansa duyarlı grafikler tembel servislerden yararlanır. Bir argümanı `#[Autowire(lazy: true)]` ile işaretlemek, örneklemeyi bağımlılık ilk kez çağrılana kadar erteler; bu, üretilen bir proxy kütüphanesi yerine PHP 8.4'ün yerel tembel nesnelerine dayanır. ```php // src/Service/ReportBuilder.php namespace App\Service; use App\Pdf\PdfRenderer; use Symfony\Component\DependencyInjection\Attribute\Autowire; final class ReportBuilder { public function __construct( // PdfRenderer is only instantiated on first actual use #[Autowire(lazy: true)] private readonly PdfRenderer $renderer, ) {} public function buildMonthly(): string { // If no method touches $this->renderer, it is never constructed return $this->renderer->render('monthly-report'); } } ``` Yerel tembel nesneler PHP 8.4 ile geldi ve [Symfony 8 ve PHP 8.4 tembel nesneleri](/blog/symfony/symfony-8-new-features-php-84-lazy-objects) kılavuzunda ayrıntılı olarak ele alındı. Kazanç, yalın kalan bir konteynerdir: PDF oluşturucular, üçüncü taraf SDK istemcileri veya rapor üreticileri gibi ağır işbirlikçiler, onlara ihtiyaç duyan kod yolu gerçekten çalışana kadar hiçbir maliyet getirmez. ## Symfony DI Mülakat Soruları ve Yanıtları Yaygın bir Symfony DI mülakat sorusu, autowiring ile autoconfiguration arasındaki farkı sorar. Autowiring, tek bir servisin yapıcı metot argümanlarını türe göre çözer; autoconfiguration ise bir servise, gerçeklediği arayüzlere dayanarak etiketler, metot çağrıları ve ayarlar uygular. Bunlar bağımsız anahtarlardır: bir servis, autoconfigure edilmeden autowire edilebilir ve tersi de geçerlidir. Bir diğer sık soru, konteynerin neden genel (public) ve özel (private) servisleri ayırdığıdır. Servisler varsayılan olarak özeldir; yani `$container->get()` ile doğrudan konteynerden alınamazlar ve yalnızca enjekte edilebilirler. Özel servisler derleme sırasında satır içine alınıp (inline) optimize edilerek kaldırılabilir, bu da daha hızlıdır; genel servisler ise alınabilir kalmalıdır, dolayısıyla optimize edici onlara dokunmaz. Servisleri konteynerden elle almak tam da bu optimizasyonu boşa çıkardığı ve bağımlılıkları gizlediği için bir anti-kalıp olarak görülür. Döngüsel bağımlılıklar klasik bir tuzak ve sık gelen bir takip sorusudur. A servisi yapıcısında B'ye, B de A'ya ihtiyaç duyarsa, konteyner ikisini de oluşturamaz ve derleme zamanında döngüsel bir başvuru bildirir. Standart çözümler şunlardır: ortak davranışı üçüncü bir servise çıkararak döngüyü kırmak, bir tarafı `#[Autowire(lazy: true)]` ile tembel enjeksiyona geçirerek bağımlılığın yalnızca ilk çağrıda çözülmesini sağlamak ya da setter enjeksiyonu kullanarak nesnenin, işbirlikçisi bağlanmadan önce var olmasını sağlamak. Mülakatçıların gerçekten dinlediği şey, döngünün yalnızca nasıl susturulacağı değil, neden bir tasarım kokusu (design smell) olduğunun kavranmasıdır. Mülakatçılar konteyner çözümlemesinin zamanlamasını da yoklar. Symfony konteyneri bir kez derleyip önbelleğe aldığından, çözülemeyen bir bağımlılık istek anında değil, önbellek ısınması sırasında ortaya çıkar. Bu garanti, derleme zamanı modelinin doğrudan bir sonucudur ve büyük Symfony uygulamalarının yük altında öngörülebilir kalmasının nedenlerinden biridir. Bu soruların daha geniş bir kümesi için [Symfony teknoloji rotası](/technologies/symfony) onları bileşene ve zorluğa göre gruplandırır. ## Sonuç - Konteynerin çalışmasına izin vermek: sınıfları `src/` altında kaydetmek, bağımlılıklara yapıcı metotta tür ipucu vermek ve manuel YAML bağlamayı tamamen atlamak. - `#[Autowire]`'a yalnızca servis olmayanlar, parametreler, ortam değişkenleri ve belirli servis kimlikleri için başvurmak. - Arayüz belirsizliğini varsayılan için `#[AsAlias]`, açık seçimler için `#[Autowire(service: ...)]` veya `#[Target]` ile çözmek. - Strateji ve eklenti kalıplarını `#[AutoconfigureTag]`, `#[AsTaggedItem]` öncelikleri ve `#[AutowireIterator]` ile yönlendirmek; tembel arama hevesli yinelemeye tercih edildiğinde `#[AutowireLocator]`'a geçmek. - Pahalı işbirlikçileri, PHP 8.4 yerel tembel nesnelerini kullanan `#[Autowire(lazy: true)]` ile ertelemek. - Servisleri alınan değil, özel ve enjekte edilen olarak tutmak; böylece derleyici grafiği satır içine alıp optimize edebilir. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/tr/blog/symfony/symfony-dependency-injection-service-container-autowiring-tags