# Service Container

### Service Container คืออะไร

Service Container เป็นส่วนเครื่องมือหลักในโครงสร้างของ Laravel Framework&#x20;

ทำหน้าที่หลักในการจัดการการโยนออบเจ็กต์  (Dependency Injection) หรือเราเรียกกันว่าฉีดออบเจ็กต์นั่นแหละครับ และการจัดการลูปการเชื่อมโยงออบเจ็กต์ (Object Binding Lifecycle) ในระบบ&#x20;

การใช้งาน Service Container ทำให้ทาง Dev สามารถกำหนดและจัดการ dependencies ของ Class ได้อย่างมีประสิทธิภาพ ช่วยให้การออกแบบซอฟต์แวร์เป็นไปตามหลักการ Single Responsibility Principle และ Interface Segregation Principle ซึ่งเป็นส่วนหนึ่งของ SOLID principles

#### ประโยชน์หลักของ Service Container

1. **การฉีดออบเจ็กต์อัตโนมัติ**

   สามารถจัดการ dependencies ของคลาสได้อัตโนมัติโดยไม่ต้องสร้างออบเจ็กต์ เช่นใน Code ชุดนี้

```php
use Illuminate\Support\ServiceProvider;
use App\PersonalWriter;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        // กำหนดการผูก (Binding) ของ dependency โดยใช้เมธอด bind
        // ซึ่งทำให้สามารถสร้างอินสแตนซ์ของ PersonalWriter ได้เมื่อมีการร้องขอการใช้งาน
        $this->app->bind(PersonalWriter::class, function ($app) {
            return new PersonalWriter();
        });
    }
}

// ทดลองใช้ใน Controller
class ExampleController extends Controller
{
    protected $writer;

    // รับ PersonalWriter ผ่านทาง constructor 
    // ซึ่งช่วยให้คลาสสามารถใช้งานอินสแตนซ์ที่ต้องการได้โดยไม่ต้องสร้างเอง
    public function __construct(PersonalWriter $writer)
    {
        $this->writer = $writer;
    }
}
```

2. **ความยืดหยุ่น**

   ช่วยให้โค้ดสามารถขยายหรือปรับแต่งได้ง่ายขึ้นโดยไม่ต้องแก้ไขในหลายๆ จุด

```php
use Illuminate\Support\ServiceProvider;
use App\ReportGeneratorInterface;
use App\MockReportGenerator;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        // ผูกอินเทอร์เฟซกับ Mock Implementation ใช้ในการทดสอบ
        $this->app->bind(ReportGeneratorInterface::class, function ($app) {
            return new MockReportGenerator();
        });
    }
}

// Controller ที่ใช้ dependency
class ReportController extends Controller
{
    protected $reportGenerator;

    // รับ ReportGeneratorInterface ผ่าน constructor
    public function __construct(ReportGeneratorInterface $reportGenerator)
    {
        $this->reportGenerator = $reportGenerator;
    }

    public function generate()
    {
        return $this->reportGenerator->generateReport();
    }
}
```

3. **การทดสอบ**

   ทำให้การทดสอบระดับหน่วย (Unit Testing) เป็นไปได้ง่ายขึ้น เพราะสามารถ mock การทำงานของ dependencies ได้ง่าย

```php
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
use App\ReportGeneratorInterface;
use App\MockReportGenerator;

class ReportControllerTest extends TestCase
{
    use RefreshDatabase;
    
    public function test_generate_report()
    {
        $this->mock(ReportGeneratorInterface::class, function ($mock) {
            $mock->shouldReceive('generateReport')->once()->andReturn('Mock Report');
        });

        $response = $this->get('/report');

        $response->assertStatus(200);
        $response->assertSee('Mock Report');
    }
}
```

4. **ความสามารถในการกำหนดค่าเอง (Binding)**

   ทาง Dev สามารถผูกอินเทอร์เฟซกับการทำงานเฉพาะเจาะจงหรือกำหนดไปยังการทำงานที่ต่างออกไปได้ เช่น

```php
use App\Contracts\PaymentGatewayInterface;
use App\Services\StripePaymentGateway;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        // Binding the interface to a specific implementation
        $this->app->bind(PaymentGatewayInterface::class, StripePaymentGateway::class);
    }
}
```

ในตัวอย่างนี้ เราจะผูก `PaymentGatewayInterface` กับ `StripePaymentGateway` ซึ่งทำให้ทุกครั้งที่มีการร้องขอ `PaymentGatewayInterface` จะได้รับอินสแตนซ์ของ `StripePaymentGateway` แทน

#### การทำงานพื้นฐาน

เมื่อมีการร้องขอออบเจ็กต์จาก Service Container, Container จะหาว่าออบเจ็กต์ขึ้นต่อ (Dependency) ใดต้องการและจะทำการสร้างออบเจ็กต์เหล่านั้นให้เอง นอกจากนี้ ยังสามารถกำหนดรูปแบบการผูก (Binding) โดยใช้ `bind` หรือ `singleton` เพื่อกำหนดว่าควรจะใช้ออบเจ็กต์เดียวกันหรือสร้างใหม่ทุกครั้งที่ร้องขอ

#### ตัวอย่างการใช้งาน

```php
use App\Services\UserService;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->bind(UserService::class, function ($app) {
            return new UserService($app->make(UserRepository::class));
        });
    }
}
```

ในตัวอย่างข้างต้น การใช้ Service Container ช่วยลดภาระในการจัดการ dependencies ของ `UserService` โดยสร้างและจัดการ `UserRepository` ที่จำเป็นสำหรับ `UserService` อัตโนมัติ


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://blog.farzai.com/parsilver/laravel/service-container.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
