SlideShare una empresa de Scribd logo
1 de 106
Descargar para leer sin conexión
從學徒變⼤大師
談 Laravel 框架擴充與套件開發
范聖佑 (Shengyou Fan)
PHPCon China 2016
2016/06/26
{	
  
	
  	
  	
  	
  "name":	
  "shengyou/self-­‐introduction",	
  
	
  	
  	
  	
  "description":	
  "⾃自我介紹",	
  
	
  	
  	
  	
  "authors":	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "name":	
  "范聖佑	
  (Shengyou	
  Fan)",	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "email":	
  "shengyoufan@gmail.com",	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "homepage":	
  "http://www.shengyoufan.com",	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "role":	
  ["Researcher",	
  "Evangelist"]	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  ],	
  
	
  	
  	
  	
  "support":	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  "facebook":	
  "http://fb.me/shengyoufan",	
  
	
  	
  	
  	
  	
  	
  	
  	
  "twitter":	
  "@shengyou",	
  
	
  	
  	
  	
  	
  	
  	
  	
  "wechat":	
  "@shengyoufan"	
  
	
  	
  	
  	
  }	
  
}
v2.2 v4.0	
  ~	
  v5.2
Page Script
5.3
探索歷程
依賴 Composer
初始化、安裝、更新全靠它
尤其是 autoloading!
全⾯面遵循 PSR
包括 PSR 1、PSR 2、PSR 4
★ 官⽅方⽂文件:https://laravel.com/
docs/5.2/contributions#coding-style
不⽌止是框架
更是完整流程
Route MVC
Schedule
Queue
Mail
Testing
Validation
從開發環境、內建元件、測試部署
⼀一條⻯⿓龍的完整框架
Cache
Session
Forge
Envoyer
Homestead Valet
內建元件
+
外掛套件
你所需要的都有
★ http://packalyst.com
★ https://socialiteproviders.github.io
Laravel 台灣
https://www.facebook.com/groups/laravel.tw
成⽴立於 2013 現有 3600 位成員加⼊入
Laravel 道場
http://www.laravel-dojo.com
致⼒力於提供最好的 Laravel 教育訓練
2016.03
正修科⼤大資⼯工系
2016.01
中華電信學院
2015.07
新北市樹林國⼩小
2014.12
彰師⼤大資⼯工系
2015.05
臺中科⼤大資⼯工系
2015.12
⻁虎尾科⼤大電算中⼼心
2016.02
交通⼤大學資服中⼼心
推廣了近三年,
最常聽到的回應是…
Laravel 看起來
好像不錯 但…
…
但
但
但…
But
But…
但
But…
導⼊入框架的疑慮
會不會被框架綁死?
框架會持續維護嗎?
有辦法跟現有專案整合嗎? 會不會很難改啊?有辦法擴充嗎?
Laravel: From Apprentice To Artisan
https://leanpub.com/laravel
框架作者 Taylor Otwell 親⾃自撰寫
說明核⼼心架構及框架擴充
從學徒變⼤大師
核⼼心機制
範例情境
• 使⽤用者在網站上註冊,註冊完會發⼀一封通知簡訊
• 使⽤用 Nexmo 簡訊寄送服務
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  寄送簡訊	
  
	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  寄送簡訊	
  
	
  	
  	
  	
  	
  	
  	
  	
  $nexmoSender	
  =	
  new	
  NexmoSender();	
  
	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  寄送簡訊	
  
	
  	
  	
  	
  	
  	
  	
  	
  $nexmoSender	
  =	
  new	
  NexmoSender();	
  
	
  	
  	
  	
  	
  	
  	
  	
  $nexmoSender-­‐>send('{PHONE}',	
  '{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  寄送簡訊	
  
	
  	
  	
  	
  	
  	
  	
  	
  $nexmoSender	
  =	
  new	
  NexmoSender();	
  
	
  	
  	
  	
  	
  	
  	
  	
  $nexmoSender-­‐>send('{PHONE}',	
  '{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
NexmoSender 和 UsersController 綁得太緊
Dependency Injection
依賴注⼊入
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  
	
  	
  	
  	
  public	
  function	
  __construct()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  public	
  function	
  register()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  $nexmoSender	
  =	
  new	
  NexmoSender();	
  
	
  	
  	
  	
  	
  	
  	
  	
  $nexmoSender-­‐>send('{PHONE}',	
  ‘{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  
	
  	
  	
  	
  public	
  function	
  __construct(NexmoSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  public	
  function	
  register()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  $nexmoSender	
  =	
  new	
  NexmoSender();	
  
	
  	
  	
  	
  	
  	
  	
  	
  $nexmoSender-­‐>send('{PHONE}',	
  ‘{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  protected	
  $smsSender;	
  
	
  	
  	
  	
  public	
  function	
  __construct(NexmoSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>smsSender	
  =	
  $smsSender;	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  public	
  function	
  register()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  $nexmoSender	
  =	
  new	
  NexmoSender();	
  
	
  	
  	
  	
  	
  	
  	
  	
  $nexmoSender-­‐>send('{PHONE}',	
  ‘{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  protected	
  $smsSender;	
  
	
  	
  	
  	
  public	
  function	
  __construct(NexmoSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>smsSender	
  =	
  $smsSender;	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  public	
  function	
  register()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  $nexmoSender	
  =	
  new	
  NexmoSender();	
  
	
  	
  	
  	
  	
  	
  	
  	
  $nexmoSender-­‐>send('{PHONE}',	
  '{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  protected	
  $smsSender;	
  
	
  	
  	
  	
  public	
  function	
  __construct(NexmoSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>smsSender	
  =	
  $smsSender;	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  public	
  function	
  register()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  $nexmoSender-­‐>send('{PHONE}',	
  '{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  protected	
  $smsSender;	
  
	
  	
  	
  	
  public	
  function	
  __construct(NexmoSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>smsSender	
  =	
  $smsSender;	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  public	
  function	
  register()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>smsSender-­‐>send('{PHONE}',	
  '{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
覺得很囉嗦?
Laravel 有⼀一招更簡單的!
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  protected	
  $smsSender;	
  
	
  	
  	
  	
  public	
  function	
  __construct(NexmoSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>smsSender	
  =	
  $smsSender;	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  public	
  function	
  register()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>smsSender-­‐>send('{PHONE}',	
  '{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  protected	
  $smsSender;	
  
	
  	
  	
  	
  public	
  function	
  __construct(NexmoSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>smsSender	
  =	
  $smsSender;	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  public	
  function	
  register(NexmoSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>smsSender-­‐>send('{PHONE}',	
  '{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  protected	
  $smsSender;	
  
	
  	
  	
  	
  public	
  function	
  __construct(NexmoSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>smsSender	
  =	
  $smsSender;	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  public	
  function	
  register(NexmoSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>smsSender-­‐>send('{PHONE}',	
  '{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  protected	
  $smsSender;	
  
	
  	
  	
  	
  public	
  function	
  __construct(NexmoSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>smsSender	
  =	
  $smsSender;	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  public	
  function	
  register(NexmoSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>send('{PHONE}',	
  '{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  public	
  function	
  register(NexmoSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>send('{PHONE}',	
  '{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
怎麼辦到的?
IoC Container
IoC 容器
Laravel 的 Service Container
1. ⺫⽬目前的 type hinting 有註冊任何綁定嗎?
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register(NexmoSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
Container
NexmoSender::class	
  =>	
  ?
1. ⺫⽬目前的 type hinting 有註冊任何綁定嗎?
2. 沒有?試著 Reflect 這個 Class,以及其相依 (遞迴)
Laravel 的 Service Container
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register(NexmoSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
} new	
  RefectionClass('NexmoSender');
Container
new	
  NexmoSender(params);
狀況題:需求變更
• 業務需求變更,要換簡訊服務商	
  
• 改⽤用	
  Twilio	
  簡訊寄送服務
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register(NexmoSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>send('{PHONE}',	
  '{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register(TwilioSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>send('{PHONE}',	
  '{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register(TwilioSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>send('{PHONE}',	
  '{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register(TwilioSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>phone('{PHONE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>message('{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>call();	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register(TwilioSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>phone('{PHONE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>message('{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>call();	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
} 只要每次有需求變更,就得修改對應的程式碼!
透過建⽴立 Interface
讓寄送簡訊的動作變得⼀一致
建⽴立契約
1. 將寄發簡訊的動作抽象成⼀一個 Interface
//	
  app/Contracts/SmsSenderContract.php	
  
interface	
  SmsSenderContract	
  
{	
  
	
  	
  	
  	
  public	
  function	
  send($phoneNumber,	
  $message);	
  
}
宣告 SmsSenderContract 並定義 methods
建⽴立契約
1. 將寄發簡訊的動作抽象成⼀一個 Interface
2. 寄送簡訊的 Class 都要實作 Interface
//	
  app/Libraries/NexmoSender.php	
  
class	
  NexmoSender	
  
{	
  
	
  	
  	
  	
  
	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  
}	
  
//	
  app/Libraries/TwilioSender.php	
  
class	
  TwilioSender	
  
{	
  
	
  	
  	
  	
  
	
  	
  	
  	
  
	
  	
  	
  
	
  	
  
}
//	
  app/Libraries/NexmoSender.php	
  
class	
  NexmoSender	
  implements	
  SmsSenderContract	
  
{	
  
	
  	
  	
  	
  public	
  function	
  send($phoneNumber,	
  $message)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}	
  
//	
  app/Libraries/TwilioSender.php	
  
class	
  TwilioSender	
  implements	
  SmsSenderContract	
  
{	
  
	
  	
  	
  	
  public	
  function	
  send($phoneNumber,	
  $message)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
} Sender 實作 SmsSenderContract 及其 methods
建⽴立契約
1. 將寄發簡訊的動作抽象成⼀一個 Interface
2. 寄送簡訊的 Class 都要實作 Interface
3. Controller 的 type hinting 改成 Interface
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register(TwilioSender	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>phone('{PHONE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>message('{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>call();	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
修改 type hinting
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register(SmsSenderContract	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>phone('{PHONE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>message('{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>call();	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register(SmsSenderContract	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>phone('{PHONE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>message('{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>call();	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
改⽤用 Interface 定義的 methods
//	
  app/Http/Controllers/UsersController.php	
  
class	
  UsersController	
  extends	
  Controller	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register(SmsSenderContract	
  $smsSender)	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>send('{PHONE}',	
  '{MESSAGE}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  }	
  
}
照著這樣的架構寫
結果出錯了?
因為 Interface 還未綁定 Class
Service Provider
服務提供者
Client
由 Service Provider 組合⽽而成
index.php
Laravel
的應⽤用程式架構
initializing
//	
  config/app.php	
  
'providers'	
  =>	
  [	
  
	
  	
  	
  	
  /*	
  
	
  	
  	
  	
  	
  *	
  Laravel	
  Framework	
  Service	
  Providers...	
  
	
  	
  	
  	
  	
  */	
  
	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  IlluminateMailMailServiceProvider::class,	
  
	
  	
  	
  	
  IlluminateQueueQueueServiceProvider::class,	
  
	
  	
  	
  	
  IlluminateViewViewServiceProvider::class,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  /*	
  
	
  	
  	
  	
  	
  *	
  Application	
  Service	
  Providers...	
  
	
  	
  	
  	
  	
  */	
  
	
  	
  	
  	
  AppProvidersAppServiceProvider::class,	
  
	
  	
  	
  	
  AppProvidersAuthServiceProvider::class,	
  
	
  	
  	
  	
  AppProvidersEventServiceProvider::class,	
  
	
  	
  	
  	
  AppProvidersRouteServiceProvider::class,	
  
],
實作 SmsServiceProvider
1. 建⽴立 SmsServiceProvider.php
$	
  php	
  artisan	
  make:provider	
  SmsServiceProvider
實作 SmsServiceProvider
1. 建⽴立 SmsServiceProvider.php
2. 在 SmsServiceProvider 裡註冊綁定、解決相依
//	
  app/Providers/SmsServiceProvider.php	
  
class	
  SmsServiceProvider	
  extends	
  ServiceProvider	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Providers/SmsServiceProvider.php	
  
class	
  SmsServiceProvider	
  extends	
  ServiceProvider	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>app-­‐>bind(	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  );	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Providers/SmsServiceProvider.php	
  
class	
  SmsServiceProvider	
  extends	
  ServiceProvider	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>app-­‐>bind(	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  SmsSenderContract::class	
  
	
  	
  	
  	
  	
  	
  	
  	
  );	
  
	
  	
  	
  	
  }	
  
}
Interface 定義
//	
  app/Providers/SmsServiceProvider.php	
  
class	
  SmsServiceProvider	
  extends	
  ServiceProvider	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>app-­‐>bind(	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  SmsSenderContract::class,	
  NexmoSender::class	
  
	
  	
  	
  	
  	
  	
  	
  	
  );	
  
	
  	
  	
  	
  }	
  
}
Interface 定義 綁定的 Class
Class 的相依參數怎麼處理?
//	
  app/Providers/SmsServiceProvider.php	
  
class	
  SmsServiceProvider	
  extends	
  ServiceProvider	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>app-­‐>bind(	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  SmsSenderContract::class,	
  NexmoSender::class	
  
	
  	
  	
  	
  	
  	
  	
  	
  );	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Providers/SmsServiceProvider.php	
  
class	
  SmsServiceProvider	
  extends	
  ServiceProvider	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>app-­‐>bind(	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  SmsSenderContract::class,	
  function()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  new	
  NexmoSender('{API_KEY}',	
  '{API_SECRET}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  });	
  
	
  	
  	
  	
  }	
  
}
第⼆二個參數改成 Closure,在 Closure 內處理
實作 SmsServiceProvider
1. 建⽴立 SmsServiceProvider.php
2. 在 SmsServiceProvider 裡註冊綁定、解決相依
3. 在 app.php 裡啟動 SmsServiceProvider
//	
  config/app.php	
  
'providers'	
  =>	
  [	
  
	
  	
  	
  	
  /*	
  
	
  	
  	
  	
  	
  *	
  Laravel	
  Framework	
  Service	
  Providers...	
  
	
  	
  	
  	
  	
  */	
  
	
  	
  	
  	
  //	
  ...	
  
	
  	
  	
  	
  IlluminateSessionSessionServiceProvider::class,	
  
	
  	
  	
  	
  AppProvidersSmsServiceProvider::class,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  /*	
  
	
  	
  	
  	
  	
  *	
  Application	
  Service	
  Providers...	
  
	
  	
  	
  	
  	
  */	
  
	
  	
  	
  	
  AppProvidersAppServiceProvider::class,	
  
	
  	
  	
  	
  //	
  ...	
  
],
聽說你寫了發送簡訊的功能,
沒問題!
我的專案也能⽤用嗎?
包成套件給你
擴充套件
發佈套件
1. 建⽴立 Composer 套件結構
Laravel 專案 SMS Package
src
Contracts
SmsSenderContract.php
Senders
NexmoSender.php
SmsServiceProvider.php
composer.json
app
Contracts
Libraries
NexmoSender.php
SmsSenderContract.php
Providers
SmsServiceProvider.php
laravel sms-pkg
發佈套件
1. 建⽴立 Composer 套件結構
2. 設定套件的 composer.json
//	
  composer.json	
  
{	
  
	
  	
  	
  	
  "name":	
  "vendor/sms-­‐pkg",	
  
	
  	
  	
  	
  "require":	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  "php":	
  ">=5.5.9",	
  
	
  	
  	
  	
  	
  	
  	
  	
  "illuminate/support":	
  "5.2.*"	
  
	
  	
  	
  	
  },	
  
	
  	
  	
  	
  "autoload":	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  "psr-­‐4":	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "MyNamespaceSms":	
  "src"	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}SMS Package
發佈套件
1. 建⽴立 Composer 套件結構
2. 設定套件的 composer.json
3. 選擇發佈套件的⽅方式
發佈管道
• 公開發佈
- 將程式碼放置在 Github 上
- 在 Packagist 上註冊套件資訊
• 私密使⽤用
- 將程式碼放置在私有版本控制系統上
- 架設 Satis 或 Toran Proxy
★ 參考:http://www.slideshare.net/shengyou/modern-web-conf-2015-php-composer
★ 參考:http://oomusou.io/laravel/laravel-package-hello-world/
怎麼安裝?
搞定!
可以使⽤用了
安裝套件
1. 設定專案的 composer.json
Laravel 專案
//	
  composer.json	
  
{	
  
	
  	
  	
  	
  "name":	
  "vendor/myproject",	
  
	
  	
  	
  	
  "require":	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  "php":	
  ">=5.5.9",	
  
	
  	
  	
  	
  	
  	
  	
  	
  "laravel/framework":	
  "5.2.*",	
  
	
  	
  	
  	
  	
  	
  	
  	
  "vendor/sms-­‐pkg":	
  "dev-­‐master"	
  
	
  	
  	
  	
  },	
  
	
  	
  	
  	
  "repositories":	
  [	
  
	
  	
  	
  	
  	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "type":	
  "path",	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  "url":	
  "../sms-­‐pkg"	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  ],	
  
}
依 repositories 現況設定 type 及 url
安裝套件
1. 設定專案的 composer.json
2. 使⽤用 Composer 更新相依套件
$	
  composer	
  update
安裝套件
1. 設定專案的 composer.json
2. 使⽤用 Composer 更新相依套件
3. 設定專案 config/app.php 內的 providers 陣列
//	
  config/app.php	
  
'providers'	
  =>	
  [	
  
	
  	
  	
  	
  /*	
  
	
  	
  	
  	
  	
  *	
  Laravel	
  Framework	
  Service	
  Providers...	
  
	
  	
  	
  	
  	
  */	
  
	
  	
  	
  	
  //...	
  
	
  	
  	
  	
  IlluminateSessionSessionServiceProvider::class,	
  
	
  	
  	
  	
  MyNamespaceProvidersSmsServiceProvider::class,	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  
	
  	
  	
  	
  /*	
  
	
  	
  	
  	
  	
  *	
  Application	
  Service	
  Providers...	
  
	
  	
  	
  	
  	
  */	
  
	
  	
  	
  	
  AppProvidersAppServiceProvider::class,	
  
	
  	
  	
  	
  //	
  ...	
  
],
讚啦!
Ta-da!
也給我⼀一份!
主題總結
今⽇日討論主題
特⾊色綜覽
依賴 Composer
全⾯面遵循 PSR
⼀一條⻯⿓龍⽅方案
完整⽣生態系
核⼼心機制
Dependency Injection
IoC Container
Service Provider
套件開發
套件結構
設定 composer.json
發佈套件
安裝套件
Too much Java?
少⼀一點套路、多⼀一點真誠?
隨機應變
⼀一切都跟需求有關
更容易了解
別⼈人的套件原理
好處 1
⾮非同步開發
好測試、好分⼯工
好處 2
//	
  app/Libraries/DummySender.php	
  
class	
  DummySender	
  implements	
  SmsSenderContract	
  
{	
  
	
  	
  	
  	
  public	
  function	
  send()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  模擬或假裝有送出簡訊	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Services/SmsServiceProvider.php	
  
class	
  SmsServiceProvider	
  extends	
  ServiceProvider	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>app-­‐>bind(	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  SmsSenderContract::class,	
  function()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  new	
  NexmoSender('{API_KEY}',	
  '{API_SECRET}');	
  
	
  	
  	
  	
  	
  	
  	
  	
  });	
  
	
  	
  	
  	
  }	
  
}
//	
  app/Services/SmsServiceProvider.php	
  
class	
  SmsServiceProvider	
  extends	
  ServiceProvider	
  
{	
  
	
  	
  	
  	
  public	
  function	
  register()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>app-­‐>bind(	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  SmsSenderContract::class,	
  function()	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  new	
  DummySender();	
  
	
  	
  	
  	
  	
  	
  	
  	
  });	
  
	
  	
  	
  	
  }	
  
}
還沒正式接上簡訊系統前
先做⼀一個假的讓程式可以運作
//	
  tests/ExampleTest.php	
  
class	
  ExampleTest	
  extends	
  TestCase	
  
{	
  
	
  	
  	
  	
  public	
  function	
  testUsersControllerSendSms()	
  
	
  	
  	
  	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  Arrange	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender	
  =	
  Mockery::mock(SmsSenderContract::class);	
  
	
  	
  	
  	
  	
  	
  	
  	
  $smsSender-­‐>shouldReceive('send')-­‐>once();	
  //	
  Assert	
  
	
  	
  	
  	
  	
  	
  	
  	
  app()-­‐>instance(SmsSenderContract::class,	
  $smsSender);	
  
	
  	
  	
  	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  //	
  Act	
  
	
  	
  	
  	
  	
  	
  	
  	
  $this-­‐>action('POST',	
  'UsersController@register');	
  
	
  	
  	
  	
  }	
  
} 使⽤用 Interface 好 Mock、好測試
隨⼼心所欲
抽換內建元件
好處 3
⼀一切照合約⾛走
Laravel Contracts
要抽換元件時,只要該元件有
實作 Interface,在 IoC 裡抽換
綁定就可以了
★ 官⽅方⽂文件:https://laravel.com/docs/5.2/contracts#how-to-use-contracts
更換樣板引擎?
• ytake/laravel-­‐smarty
- 將 Smarty 樣板引擎整合⾄至 Laravel
• rcrowe/twigbridge
- 將 Twig 樣板引擎整合⾄至 Laravel
★ 參考:https://github.com/ytake/Laravel.Smarty
★ 參考:https://github.com/rcrowe/TwigBridge
⼯工商服務
歡迎⼤大家來台灣玩!
PHPConf Taiwan 2016
年度 PHP 盛會,將於 2016/10/29 舉辦
PHP 也有 Day
每⽉月舉辦⼀一次的 PHP 講座型聚會
Laradiner
每⽉月舉辦⼀一次的 Laravel 讀書會
Laradebut
每⽉月舉辦⼀一次的 Laravel 新⼿手村
Vuediner
與友團合辦的Vue.js 讀書會
Q & A
感謝聆聽.歡迎交流

Más contenido relacionado

La actualidad más candente

[PHPConf Taiwan 2015] 跟著 Laravel 5.1 一起成為更好的 PHP 開發者
[PHPConf Taiwan 2015] 跟著 Laravel 5.1 一起成為更好的 PHP 開發者[PHPConf Taiwan 2015] 跟著 Laravel 5.1 一起成為更好的 PHP 開發者
[PHPConf Taiwan 2015] 跟著 Laravel 5.1 一起成為更好的 PHP 開發者Shengyou Fan
 
Introduction to Perl - Day 2
Introduction to Perl - Day 2Introduction to Perl - Day 2
Introduction to Perl - Day 2Dave Cross
 
Attacking thru HTTP Host header
Attacking thru HTTP Host headerAttacking thru HTTP Host header
Attacking thru HTTP Host headerSergey Belov
 
AEM hacker - approaching Adobe Experience Manager webapps in bug bounty programs
AEM hacker - approaching Adobe Experience Manager webapps in bug bounty programsAEM hacker - approaching Adobe Experience Manager webapps in bug bounty programs
AEM hacker - approaching Adobe Experience Manager webapps in bug bounty programsMikhail Egorov
 
Nginx internals
Nginx internalsNginx internals
Nginx internalsliqiang xu
 
啟動 Laravel 與環境設定
啟動 Laravel 與環境設定啟動 Laravel 與環境設定
啟動 Laravel 與環境設定Shengyou Fan
 
Neat tricks to bypass CSRF-protection
Neat tricks to bypass CSRF-protectionNeat tricks to bypass CSRF-protection
Neat tricks to bypass CSRF-protectionMikhail Egorov
 
From Generator to Fiber the Road to Coroutine in PHP
From Generator to Fiber the Road to Coroutine in PHPFrom Generator to Fiber the Road to Coroutine in PHP
From Generator to Fiber the Road to Coroutine in PHPAlbert Chen
 
Mikhail Egorov - Hunting for bugs in Adobe Experience Manager webapps
Mikhail Egorov - Hunting for bugs in Adobe Experience Manager webappsMikhail Egorov - Hunting for bugs in Adobe Experience Manager webapps
Mikhail Egorov - Hunting for bugs in Adobe Experience Manager webappshacktivity
 
Nginx Internals
Nginx InternalsNginx Internals
Nginx InternalsJoshua Zhu
 
Reverse proxies & Inconsistency
Reverse proxies & InconsistencyReverse proxies & Inconsistency
Reverse proxies & InconsistencyGreenD0g
 
2021.laravelconf.tw.slides1
2021.laravelconf.tw.slides12021.laravelconf.tw.slides1
2021.laravelconf.tw.slides1LiviaLiaoFontech
 
Extending Java EE with CDI and JBoss Forge
Extending Java EE with CDI and JBoss ForgeExtending Java EE with CDI and JBoss Forge
Extending Java EE with CDI and JBoss ForgeAntoine Sabot-Durand
 
Introduction to Perl - Day 1
Introduction to Perl - Day 1Introduction to Perl - Day 1
Introduction to Perl - Day 1Dave Cross
 
Spring MVC to iOS and the REST
Spring MVC to iOS and the RESTSpring MVC to iOS and the REST
Spring MVC to iOS and the RESTRoy Clarkson
 
Security in PHP - 那些在滲透測試的小技巧
Security in PHP - 那些在滲透測試的小技巧Security in PHP - 那些在滲透測試的小技巧
Security in PHP - 那些在滲透測試的小技巧Orange Tsai
 
What should a hacker know about WebDav?
What should a hacker know about WebDav?What should a hacker know about WebDav?
What should a hacker know about WebDav?Mikhail Egorov
 

La actualidad más candente (20)

[PHPConf Taiwan 2015] 跟著 Laravel 5.1 一起成為更好的 PHP 開發者
[PHPConf Taiwan 2015] 跟著 Laravel 5.1 一起成為更好的 PHP 開發者[PHPConf Taiwan 2015] 跟著 Laravel 5.1 一起成為更好的 PHP 開發者
[PHPConf Taiwan 2015] 跟著 Laravel 5.1 一起成為更好的 PHP 開發者
 
Introduction to Perl - Day 2
Introduction to Perl - Day 2Introduction to Perl - Day 2
Introduction to Perl - Day 2
 
Attacking thru HTTP Host header
Attacking thru HTTP Host headerAttacking thru HTTP Host header
Attacking thru HTTP Host header
 
AEM hacker - approaching Adobe Experience Manager webapps in bug bounty programs
AEM hacker - approaching Adobe Experience Manager webapps in bug bounty programsAEM hacker - approaching Adobe Experience Manager webapps in bug bounty programs
AEM hacker - approaching Adobe Experience Manager webapps in bug bounty programs
 
Nginx internals
Nginx internalsNginx internals
Nginx internals
 
啟動 Laravel 與環境設定
啟動 Laravel 與環境設定啟動 Laravel 與環境設定
啟動 Laravel 與環境設定
 
Neat tricks to bypass CSRF-protection
Neat tricks to bypass CSRF-protectionNeat tricks to bypass CSRF-protection
Neat tricks to bypass CSRF-protection
 
Offzone | Another waf bypass
Offzone | Another waf bypassOffzone | Another waf bypass
Offzone | Another waf bypass
 
From Generator to Fiber the Road to Coroutine in PHP
From Generator to Fiber the Road to Coroutine in PHPFrom Generator to Fiber the Road to Coroutine in PHP
From Generator to Fiber the Road to Coroutine in PHP
 
Mikhail Egorov - Hunting for bugs in Adobe Experience Manager webapps
Mikhail Egorov - Hunting for bugs in Adobe Experience Manager webappsMikhail Egorov - Hunting for bugs in Adobe Experience Manager webapps
Mikhail Egorov - Hunting for bugs in Adobe Experience Manager webapps
 
Nginx Internals
Nginx InternalsNginx Internals
Nginx Internals
 
Reverse proxies & Inconsistency
Reverse proxies & InconsistencyReverse proxies & Inconsistency
Reverse proxies & Inconsistency
 
2021.laravelconf.tw.slides1
2021.laravelconf.tw.slides12021.laravelconf.tw.slides1
2021.laravelconf.tw.slides1
 
Extending Java EE with CDI and JBoss Forge
Extending Java EE with CDI and JBoss ForgeExtending Java EE with CDI and JBoss Forge
Extending Java EE with CDI and JBoss Forge
 
Introduction to Perl - Day 1
Introduction to Perl - Day 1Introduction to Perl - Day 1
Introduction to Perl - Day 1
 
Spring MVC to iOS and the REST
Spring MVC to iOS and the RESTSpring MVC to iOS and the REST
Spring MVC to iOS and the REST
 
PHP
PHPPHP
PHP
 
Security in PHP - 那些在滲透測試的小技巧
Security in PHP - 那些在滲透測試的小技巧Security in PHP - 那些在滲透測試的小技巧
Security in PHP - 那些在滲透測試的小技巧
 
What should a hacker know about WebDav?
What should a hacker know about WebDav?What should a hacker know about WebDav?
What should a hacker know about WebDav?
 
Php Presentation
Php PresentationPhp Presentation
Php Presentation
 

Similar a PHPCon China 2016 - 從學徒變大師:談 Laravel 框架擴充與套件開發

從 Web Site 到 Web Application,從 Web Services 到 Mobile Services
從 Web Site 到 Web Application,從 Web Services 到 Mobile Services從 Web Site 到 Web Application,從 Web Services 到 Mobile Services
從 Web Site 到 Web Application,從 Web Services 到 Mobile ServicesKuo-Chun Su
 
javascript的分层概念 --- 阿当
javascript的分层概念 --- 阿当javascript的分层概念 --- 阿当
javascript的分层概念 --- 阿当裕波 周
 
[Modern Web 2016] 讓你的 PHP 開發流程再次潮起來
[Modern Web 2016] 讓你的 PHP 開發流程再次潮起來[Modern Web 2016] 讓你的 PHP 開發流程再次潮起來
[Modern Web 2016] 讓你的 PHP 開發流程再次潮起來Shengyou Fan
 
Ajax Transportation Methods
Ajax Transportation MethodsAjax Transportation Methods
Ajax Transportation Methodsyiditushe
 
YUI ─ 阿大
YUI ─ 阿大YUI ─ 阿大
YUI ─ 阿大taobao.com
 
Handler socket测试报告 - 20110422
Handler socket测试报告 - 20110422Handler socket测试报告 - 20110422
Handler socket测试报告 - 20110422Jinrong Ye
 
Slide 20120322
Slide 20120322Slide 20120322
Slide 20120322Yubei Li
 
Asp.net mvc 培训
Asp.net mvc 培训Asp.net mvc 培训
Asp.net mvc 培训lotusprince
 
透過 Windows Azure Mobile Services 開發各平台 Apps
透過 Windows Azure Mobile Services 開發各平台 Apps透過 Windows Azure Mobile Services 開發各平台 Apps
透過 Windows Azure Mobile Services 開發各平台 AppsEric ShangKuan
 
利用Signalr打造即時通訊@Tech day geek
利用Signalr打造即時通訊@Tech day geek利用Signalr打造即時通訊@Tech day geek
利用Signalr打造即時通訊@Tech day geekJohnson Gau
 
Flex 4.5 action data communication
Flex 4.5 action data communicationFlex 4.5 action data communication
Flex 4.5 action data communicationjexchan
 
Angular Meetup 04 - Angular PWA 之沒有網路的日子 20190731
Angular Meetup 04 - Angular PWA 之沒有網路的日子 20190731Angular Meetup 04 - Angular PWA 之沒有網路的日子 20190731
Angular Meetup 04 - Angular PWA 之沒有網路的日子 20190731升煌 黃
 
twMVC#32應用 ASP.NET WebAPI2 Odata 建置高互動性 APIS
twMVC#32應用 ASP.NET WebAPI2 Odata 建置高互動性 APIStwMVC#32應用 ASP.NET WebAPI2 Odata 建置高互動性 APIS
twMVC#32應用 ASP.NET WebAPI2 Odata 建置高互動性 APIStwMVC
 
Rest Ruby On Rails
Rest Ruby On RailsRest Ruby On Rails
Rest Ruby On Railsshaokun
 
用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Servicesjavatwo2011
 
Javascript之昨是今非
Javascript之昨是今非Javascript之昨是今非
Javascript之昨是今非Tony Deng
 
PHP & MySQL 教學
PHP & MySQL 教學PHP & MySQL 教學
PHP & MySQL 教學Bo-Yi Wu
 
4, workflow tables & api
4, workflow tables & api4, workflow tables & api
4, workflow tables & apited-xu
 

Similar a PHPCon China 2016 - 從學徒變大師:談 Laravel 框架擴充與套件開發 (20)

從 Web Site 到 Web Application,從 Web Services 到 Mobile Services
從 Web Site 到 Web Application,從 Web Services 到 Mobile Services從 Web Site 到 Web Application,從 Web Services 到 Mobile Services
從 Web Site 到 Web Application,從 Web Services 到 Mobile Services
 
javascript的分层概念 --- 阿当
javascript的分层概念 --- 阿当javascript的分层概念 --- 阿当
javascript的分层概念 --- 阿当
 
[Modern Web 2016] 讓你的 PHP 開發流程再次潮起來
[Modern Web 2016] 讓你的 PHP 開發流程再次潮起來[Modern Web 2016] 讓你的 PHP 開發流程再次潮起來
[Modern Web 2016] 讓你的 PHP 開發流程再次潮起來
 
Ajax Transportation Methods
Ajax Transportation MethodsAjax Transportation Methods
Ajax Transportation Methods
 
YUI ─ 阿大
YUI ─ 阿大YUI ─ 阿大
YUI ─ 阿大
 
Handler socket测试报告 - 20110422
Handler socket测试报告 - 20110422Handler socket测试报告 - 20110422
Handler socket测试报告 - 20110422
 
Slide 20120322
Slide 20120322Slide 20120322
Slide 20120322
 
Asp.net mvc 培训
Asp.net mvc 培训Asp.net mvc 培训
Asp.net mvc 培训
 
透過 Windows Azure Mobile Services 開發各平台 Apps
透過 Windows Azure Mobile Services 開發各平台 Apps透過 Windows Azure Mobile Services 開發各平台 Apps
透過 Windows Azure Mobile Services 開發各平台 Apps
 
利用Signalr打造即時通訊@Tech day geek
利用Signalr打造即時通訊@Tech day geek利用Signalr打造即時通訊@Tech day geek
利用Signalr打造即時通訊@Tech day geek
 
Flex 4.5 action data communication
Flex 4.5 action data communicationFlex 4.5 action data communication
Flex 4.5 action data communication
 
Angular Meetup 04 - Angular PWA 之沒有網路的日子 20190731
Angular Meetup 04 - Angular PWA 之沒有網路的日子 20190731Angular Meetup 04 - Angular PWA 之沒有網路的日子 20190731
Angular Meetup 04 - Angular PWA 之沒有網路的日子 20190731
 
CRUD 綜合運用
CRUD 綜合運用CRUD 綜合運用
CRUD 綜合運用
 
twMVC#32應用 ASP.NET WebAPI2 Odata 建置高互動性 APIS
twMVC#32應用 ASP.NET WebAPI2 Odata 建置高互動性 APIStwMVC#32應用 ASP.NET WebAPI2 Odata 建置高互動性 APIS
twMVC#32應用 ASP.NET WebAPI2 Odata 建置高互動性 APIS
 
Rest Ruby On Rails
Rest Ruby On RailsRest Ruby On Rails
Rest Ruby On Rails
 
用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services用JAX-RS和Jersey完成RESTful Web Services
用JAX-RS和Jersey完成RESTful Web Services
 
Javascript之昨是今非
Javascript之昨是今非Javascript之昨是今非
Javascript之昨是今非
 
PHP & MySQL 教學
PHP & MySQL 教學PHP & MySQL 教學
PHP & MySQL 教學
 
4, workflow tables & api
4, workflow tables & api4, workflow tables & api
4, workflow tables & api
 
nodejs开发web站点
nodejs开发web站点nodejs开发web站点
nodejs开发web站点
 

Más de Shengyou Fan

[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式Shengyou Fan
 
[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...
[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...
[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...Shengyou Fan
 
[Kotlin 讀書會第五梯次] 深入淺出 Kotlin 第一章導讀
[Kotlin 讀書會第五梯次] 深入淺出 Kotlin 第一章導讀[Kotlin 讀書會第五梯次] 深入淺出 Kotlin 第一章導讀
[Kotlin 讀書會第五梯次] 深入淺出 Kotlin 第一章導讀Shengyou Fan
 
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能Shengyou Fan
 
How I make a podcast website using serverless technology in 2023
How I make a podcast website using serverless technology in 2023How I make a podcast website using serverless technology in 2023
How I make a podcast website using serverless technology in 2023Shengyou Fan
 
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀Shengyou Fan
 
[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台
[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台
[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台Shengyou Fan
 
[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇
[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇
[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇Shengyou Fan
 
Using the Exposed SQL Framework to Manage Your Database
Using the Exposed SQL Framework to Manage Your DatabaseUsing the Exposed SQL Framework to Manage Your Database
Using the Exposed SQL Framework to Manage Your DatabaseShengyou Fan
 
[COSCUP 2022] Kotlin Collection 遊樂園
[COSCUP 2022] Kotlin Collection 遊樂園[COSCUP 2022] Kotlin Collection 遊樂園
[COSCUP 2022] Kotlin Collection 遊樂園Shengyou Fan
 
初探 Kotlin Multiplatform
初探 Kotlin Multiplatform初探 Kotlin Multiplatform
初探 Kotlin MultiplatformShengyou Fan
 
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率Shengyou Fan
 
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用Shengyou Fan
 
Composer 經典食譜
Composer 經典食譜Composer 經典食譜
Composer 經典食譜Shengyou Fan
 
老派浪漫:用 Kotlin 寫 Command Line 工具
老派浪漫:用 Kotlin 寫 Command Line 工具老派浪漫:用 Kotlin 寫 Command Line 工具
老派浪漫:用 Kotlin 寫 Command Line 工具Shengyou Fan
 
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS AggregatorShengyou Fan
 
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON APIShengyou Fan
 
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin ServerlessShengyou Fan
 
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置Shengyou Fan
 
用 Kotlin 打造讀書會小幫手
用 Kotlin 打造讀書會小幫手用 Kotlin 打造讀書會小幫手
用 Kotlin 打造讀書會小幫手Shengyou Fan
 

Más de Shengyou Fan (20)

[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
[GDG Kaohsiung DevFest 2023] 以 Compose 及 Kotlin Multiplatform 打造多平台應用程式
 
[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...
[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...
[JCConf 2023] 從 Kotlin Multiplatform 到 Compose Multiplatform:在多平台間輕鬆共用業務邏輯與 U...
 
[Kotlin 讀書會第五梯次] 深入淺出 Kotlin 第一章導讀
[Kotlin 讀書會第五梯次] 深入淺出 Kotlin 第一章導讀[Kotlin 讀書會第五梯次] 深入淺出 Kotlin 第一章導讀
[Kotlin 讀書會第五梯次] 深入淺出 Kotlin 第一章導讀
 
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
[WebConf Taiwan 2023] 一份 Zend Engine 外帶!透過 Micro 讓一次打包、多處運行變得可能
 
How I make a podcast website using serverless technology in 2023
How I make a podcast website using serverless technology in 2023How I make a podcast website using serverless technology in 2023
How I make a podcast website using serverless technology in 2023
 
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀
[Effective Kotlin 讀書會] 第八章 Efficient collection processing 導讀
 
[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台
[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台
[MOPCON 2022] 以 Kotlin Multiplatform 制霸全平台
 
[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇
[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇
[JCConf 2022] Compose for Desktop - 開發桌面軟體的新選擇
 
Using the Exposed SQL Framework to Manage Your Database
Using the Exposed SQL Framework to Manage Your DatabaseUsing the Exposed SQL Framework to Manage Your Database
Using the Exposed SQL Framework to Manage Your Database
 
[COSCUP 2022] Kotlin Collection 遊樂園
[COSCUP 2022] Kotlin Collection 遊樂園[COSCUP 2022] Kotlin Collection 遊樂園
[COSCUP 2022] Kotlin Collection 遊樂園
 
初探 Kotlin Multiplatform
初探 Kotlin Multiplatform初探 Kotlin Multiplatform
初探 Kotlin Multiplatform
 
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
簡化 JVM 上雲 - 透過 Azure Spring Cloud 提升開發、發佈及服務監控效率
 
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
以 Kotlin Multiplatform Mobile (KMM) 開發跨平台行動應用
 
Composer 經典食譜
Composer 經典食譜Composer 經典食譜
Composer 經典食譜
 
老派浪漫:用 Kotlin 寫 Command Line 工具
老派浪漫:用 Kotlin 寫 Command Line 工具老派浪漫:用 Kotlin 寫 Command Line 工具
老派浪漫:用 Kotlin 寫 Command Line 工具
 
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
[Kotlin Serverless 工作坊] 單元 4 - 實作 RSS Aggregator
 
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
[Kotlin Serverless 工作坊] 單元 3 - 實作 JSON API
 
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
[Kotlin Serverless 工作坊] 單元 2 - 簡介 Kotlin Serverless
 
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
[Kotlin Serverless 工作坊] 單元 1 - 開發環境建置
 
用 Kotlin 打造讀書會小幫手
用 Kotlin 打造讀書會小幫手用 Kotlin 打造讀書會小幫手
用 Kotlin 打造讀書會小幫手
 

PHPCon China 2016 - 從學徒變大師:談 Laravel 框架擴充與套件開發