การสร้างความสามารถในการส่งเข้า
ใน webman การสร้างความสามารถในการส่งเข้าเป็นคุณสมบัติที่เลือกได้ คุณสมบัตินี้ถูกปิดไว้โดยค่าเริ่มต้น หากคุณต้องการสร้างความสามารถในการส่งเข้า แนะนำให้ใช้php-di ต่อไปคือวิธีการใช้ webman ร่วมกับ php-di
การติดตั้ง
composer require psr/container ^1.1.1 php-di/php-di ^6 doctrine/annotations ^1.14
แก้ไขการตั้งค่า config/container.php
ให้เป็นดังนี้
$builder = new \DI\ContainerBuilder();
$builder->addDefinitions(config('dependence', []));
$builder->useAutowiring(true);
$builder->useAnnotations(true);
return $builder->build();
config/container.php
ต้องคืนการสร้างตัวอย่างที่เป็นไปตามมาตรฐานPSR-11
ถ้าคุณไม่ต้องการใช้php-di
คุณสามารถสร้างและคืนตัวอย่างอื่นที่เป็นไปตามมาตรฐานPSR-11
ที่นี่
การส่งตัวให้นำมาใช้
สร้าง app/service/Mailer.php
(ถ้าโฟลเดอร์ไม่มีให้สร้างขึ้นมาเอง) โดยมีเนื้อหาดังนี้
<?php
namespace app\service;
class Mailer
{
public function mail($email, $content)
{
// โค้ดส่งอีเมลล์ของคุณ
}
}
เนื้อหาของ app/controller/UserController.php
ดังนี้
<?php
namespace app\controller;
use support\Request;
use app\service\Mailer;
class UserController
{
private $mailer;
public function __construct(Mailer $mailer)
{
$this->mailer = $mailer;
}
public function register(Request $request)
{
$this->mailer->mail('hello@webman.com', 'Hello and welcome!');
return response('ok');
}
}
ตามปกติต้องมีการใช้โค้ดนี้เพื่อทำให้ app\controller\UserController
ได้ยิ่งไปกับการสร้างโดยตั้งชื่อตัวแปรประเภท Mailer ไว้ดังนี้
$mailer = new Mailer;
$user = new UserController($mailer);
เมื่อใช้ php-di
นักพัฒนาไม่จำเป็นต้องสร้างตัวแปรของ Mailer
ในคอนโทลเลอร์ เพราะ webman จะทำให้ด้วยเอง ถ้าต้องการใช้คลาสอื่นในการสร้าง Mailer
ก็จะทำการสร้างและส่งเข้าโดยอัตโนมัติ นักพัฒนาไม่จำเป็นต้องทำงานเริ่มต้นใด ๆ
หมายเหตุ
ต้องมีการสร้างตัวอย่างที่ถูกสร้างด้วย webman หรือphp-di
เท่านั้นที่จะสามารถส่งเข้าอัตโนมัติได้ การสร้างตัวเองด้วยคำสั่งnew
ไม่สามารถส่งเข้าอัตโนมัติ หากต้องการส่งเข้าจะต้องใช้support\Container
อินเทอร์เฟซแทนคำสั่งnew
เช่น
use app\service\UserService;
use app\service\LogService;
use support\Container;
// สร้างตัวตามคำสั่ง new ไม่สามารถทำให้ส่งเข้าได้
$user_service = new UserService;
// สร้างตัวตามคำสั่ง new ไม่สามารถทำให้ส่งเข้าได้
$log_service = new LogService($path, $name);
// สร้างตัวโดยใช้ Container เพื่อทำให้สามารถส่งเข้าได้
$user_service = Container::get(UserService::class);
// สร้างตัวโดยใช้ Container เพื่อทำให้สามารถส่งเข้าได้
$log_service = Container::make(LogService::class, [$path, $name]);
ส่งเข้าโดยใช้คำอธิบาย
นอกจากการส่งเข้าการสร้างตัวด้วยสร้อยการู้ ยังสามารถใช้การส่งเข้าโดยใช้คำอธิบายได้อีกด้วย ตัดเช่นตัวอย่างที่กำหนดไว้ข้างต้น app\controller\UserController
การเปลี่ยนแปลงเป็นดังนี้
<?php
namespace app\controller;
use support\Request;
use app\service\Mailer;
use DI\Annotation\Inject;
class UserController
{
/**
* @Inject
* @var Mailer
*/
private $mailer;
public function register(Request $request)
{
$this->mailer->mail('hello@webman.com', 'Hello and welcome!');
return response('ok');
}
}
โดยตัวอย่างนี้ผ่านการใช้ @Inject
การส่งเข้าภูมิการ์ และได้ทำการประกาศประเภทวัตถุด้วย @var
โดยตัวอย่างนี้และการส่งเข้าตามคำอธิบายได้ทำซ้ำเอฟเฟกต์กับ การส่งเข้าตามสร้างตัว แต่โค้ดสั้นกว่า
หมายเหตุ
เวอร์ชันก่อนหน้าที่เขียนโค้ดนี้ webman ไม่รองรับการส่งพารามิเตอร์ของคอนโทลเลอร์ เช่น โค้ดนี้เมื่อ webman<=1.4.6 จะไม่รองรับ
<?php
namespace app\controller;
use support\Request;
use app\service\Mailer;
class UserController
{
// มีการส่งพารามิเตอร์ของคอนโทลเลอร์ไม่รองรับก่อนเวอร์ชัน 1.4.6
public function register(Request $request, Mailer $mailer)
{
$mailer->mail('hello@webman.com', 'Hello and welcome!');
return response('ok');
}
}
การสร้างตัวอย่างการส่งเข้าเองเอง
เวลาในบางครั้งพารามิเตอร์ที่ผ่านการสร้างตัวอย่างอาจจะไม่ใช่ตัวอย่างของคลาส แต่อาจจะเป็นสตริง, เลข, อาเรย์ และอื่น ๆ ตัวอย่างเช่น Mailer จำเป็นต้องผ่านการส่ง smpt server ip และ port:
<?php
namespace app\service;
class Mailer
{
private $smtpHost;
private $smtpPort;
public function __construct($smtp_host, $smtp_port)
{
$this->smtpHost = $smtp_host;
$this->smtpPort = $smtp_port;
}
public function mail($email, $content)
{
// โค้ดส่งอีเมลล์ของคุณ
}
}
การส่งเข้าด้วยตนเองจะไม่สามารถใช้สร้างตัวอย่างที่ผ่านการสร้างตัวอย่างได้เนื่องจาก php-di
ไม่สามารถระบุค่าของ $smtp_host
$smtp_port
ได้ ในกรณีนี้ลองใช้การส่งเข้าโดยกำหนดเอง
ใน config/dependence.php
(หากไม่มีไฟล์นี้ให้สร้างขึ้นมาเอง) อย่างนี้:
return [
// ... การตั้งค่าส่วนต่อ
app\service\Mailer::class => new app\service\Mailer('192.168.1.11', 25);
];
นี่คือการสร้างเมื่อต้องการผ่านการสร้างตัวอย่างคอลสการีเป็นตัวอย่างให้ app\service\Mailer
โดยระบบจะทำการส่งโดยอัตโนมัติ app\service\Mailer
ระหับตัวอย่างที่สร้างไว้ในคอสนี้
เราสังเกตได้ว่า config/dependence.php
ใช้คำสั่ง new
ในการสร้าง Mailer
นั้นไม่มีปัญหาในตัวอย่างนี้ แต่มองการว่าถ้า Mailer
อีกรูปแบบจะต้องผ่านการสร้างด้วย new
สร้างตัวเองข้อมูลผ่านการสสร้างตัวอย่างของคอลสหไม่สามารถส่งเข้าได้ วิธีการแก้ไขคือใช้การส่งเข้าระหว่างฟฟฟ ย้ำ Container::get(ชื่อคลาส)
หรือ Container::make(ชื่อคลาส, [พารามิเตอร์ของคอนโทลเลอร์])
เพื่อสร้างคลาส
การฝังอินเทอร์เฟซที่กำหนดเอง
ในโครงการจริงเราต้องการโปรแกรมตามหลักการของอินเทอร์เฟซ แทนที่จะเป็นคลาสที่เฉพาะเจาะจง เช่น app\controller\UserController
ควรจะ include app\service\MailerInterface
แทนที่จะ include app\service\Mailer
กำหนดอินเทอร์เฟซ MailerInterface
ดังนี้
<?php
namespace app\service;
interface MailerInterface
{
public function mail($email, $content);
}
กำหนดการปฏิบัติตามอินเทอร์เฟซ MailerInterface
<?php
namespace app\service;
class Mailer implements MailerInterface
{
private $smtpHost;
private $smtpPort;
public function __construct($smtp_host, $smtp_port)
{
$this->smtpHost = $smtp_host;
$this->smtpPort = $smtp_port;
}
public function mail($email, $content)
{
// ข้อความส่งออกจะถูกละเลย
}
}
Include อินเทอร์เฟซ MailerInterface
แทนที่จะมีการปฏิบัติตามตัวเอง
<?php
namespace app\controller;
use support\Request;
use app\service\MailerInterface;
use DI\Annotation\Inject;
class UserController
{
/**
* @Inject
* @var MailerInterface
*/
private $mailer;
public function register(Request $request)
{
$this->mailer->mail('hello@webman.com', 'สวัสดีและยินดีต้อนรับ!');
return response('ok');
}
}
config/dependence.php
ถูกกำหนดตามอินเทอร์เฟซ MailerInterface
ดังนี้
use Psr\Container\ContainerInterface;
return [
app\service\MailerInterface::class => function(ContainerInterface $container) {
return $container->make(app\service\Mailer::class, ['smtp_host' => '192.168.1.11', 'smtp_port' => 25]);
}
];
นั่นคือเมื่อธุรกิจต้องการใช้ MailerInterface
อินเทอร์เฟซ จะถูกใช้ Mailer
สิ่งที่ดำเนินการ
ประโยชน์ของการใช้อินเทอร์เฟซคือ เมื่อเราต้องการเปลี่ยนคอมโพเนนต์ใด ๆ เราไม่จำเป็นต้องเปลี่ยนโค้ดทำธุรกิจ แค่ต้องการเปลี่ยนการปฏิบัติตามใน
config/dependence.php
เท่านั้น สิ่งนี้ก็เป็นประโยชน์มากในการทดสอบของหน่วย
การฝังอินเจคอื่นๆ
ใน config/dependence.php
สามารถกำหนดค่าต่างๆของคลาสอื่นคลาส เช่น สตริง ตัวเลข อาเรย์ และอื่นๆ
เช่น config/dependence.php
ถูกกำหนดดังนี้
return [
'smtp_host' => '192.168.1.11',
'smtp_port' => 25
];
นี้เวลาเราสามารถใช้ @Inject
เพื่อฝัง smtp_host
smtp_port
เข้าไปในแอตทริบิวต์
<?php
namespace app\service;
use DI\Annotation\Inject;
class Mailer
{
/**
* @Inject("smtp_host")
*/
private $smtpHost;
/**
* @Inject("smtp_port")
*/
private $smtpPort;
public function mail($email, $content)
{
// ข้อความส่งออกจะถูกละเลย
echo "{$this->smtpHost}:{$this->smtpPort}\n"; // ผลลัพธ์จะเอา 192.168.1.11:25
}
}
โปรดทราบ:
@Inject("key")
ในนั้นมีเครื่องหมายคำพูดคู่
เนื้อหาเพิ่มเติม
โปรดอ้างถึงคู่มือ php-di