å¼ç¤¾æè¡ããã°ã¸ãè¶ãã®ã¿ãªãã¾ãããã«ã¡ã¯ãä»å¹´åº¦å
¥ç¤¾ã®æ°äººã YamaYuski ã§ãã
å
æ¥ã社å
åå¼·ä¼ã«ã¦ãtraitã使ã£ã¦æ¥½ããã話ãã¨ããæ¼ç®ã§ç°¡åã« trait ã«ã¤ãã¦çºè¡¨ãã¾ããã
trait ãå®è£
ããã PHP5.4 ã¯2å¹´ãåã«ãªãªã¼ã¹ããããã®ãªã®ã§ãä½æ
ä»æ´ãã¨ãã話ã«ãªãã¨æãã¾ãã
ãããããããä¸(ç¹ã«æ¥æ¬èªå)ã«ããã¦ã® trait ã®è¨äºã¯ã¾ã ã¾ã å°ãªããå
·ä½ä¾ãæ¢ãã®ã大å¤ã ã£ãã®ã§ãããããã㦠trait ã¯ãã¾ã浸éãã¦ããªãããããªããï¼ãã¨èãã trait ã®æç¨æ§ãä¸ã«åºããããã«ãã®è¨äºãä½ãå§ãã¾ããã
ä»åã¯ãåå¿è
ãªããå人çã«èª¿ã¹ããèããããããã¨ãã
- trait ã¨ã¯ãªã«ã
- trait ã®å®è£ æ¹æ³ã¨å©ç¨æ¹æ³
- ã©ã®ãããªã±ã¼ã¹ã§å®è£ ããã
- å®è£ æã®å°ãã¿
ã®4ç¹ã«çµã£ã¦ãç´¹ä»ãããã¨æãã¾ãã
1. trait ã¨ã¯ãªã«ã
ä»åããã§ã¯ãä½æ
trait ã¨ããæ©è½ãæè¼ããããããç´¹ä»ãã¾ãã
æ¦è¦ã«é¢ãã¦ã¯å
¬å¼ã®ããã¥ã¢ã«ãé常ã«æå¿«ãªè§£èª¬ããã¦ããã®ã§ãæ¯éãèªã¿ãã ããã
çµè«ããè¨ãã¨ã trait 㯅
å®è£
ã³ã¼ãã®åå©ç¨æ§ãåä¸ãããã¢ããªã±ã¼ã·ã§ã³ã®å®è£
ã³ã¼ããããã·ã³ãã«ã«ãããã
ã«æè¼ããã¾ããã
ãããã trait ãå°å
¥ãããèæ¯ã¯ãPHPã®ãå¤éç¶æ¿ãåºæ¥ãªããã¨ããåé¡ã解決ããã¨ããé¨åã«ããã¾ãã
è¤æ°ã®ã¯ã©ã¹ã§å¤§ä½åããããªæ©è½ã¨ãªãã
- ãã¼ã¿ãã¼ã¹ããã£ãã·ã¥ãªã©ã®ããã¼ã¿ã¸ã®ã¢ã¯ã»ã¹
- SingletonãFactoryãªã©ã®ãã¶ã¤ã³ãã¿ã¼ã³ã®å®è£
- ã¢ãã«ã¯ã©ã¹ã®ã¢ã¯ã»ãµ
- …
ãªã©ããåã
ã®ã¯ã©ã¹ã§å®è£
ãã㨅
ã½ã¼ã¹ã³ã¼ãã®ã³ãã¼ã¢ã³ããã¼ã¹ããå¢ãã¾ãã
ã³ãã¼ã¢ã³ããã¼ã¹ãã¨ããã®ã¯ãã½ã¼ã¹ã³ã¼ãã®åå©ç¨æ§â» ã®è¦³ç¹ããåºæ¥ãã ã使ããªãããã«ããã®ãè¯ãã¨ããã¦ãã¾ãã
â»åè : ã³ã¼ãã®åå©ç¨ – Wikipedia
ããã¾ã§ã®PHPã§ã¯ç¶æ¿ãè¡ããã¨ã§å®è£
ã³ã¼ããåå©ç¨ãããã¨ãå¯è½ã§ããããä¾ãã°
ãã¢ãã«ãã¼ã¿ã®æä½ãåºæ¥ã¦ããã¤ã¤ã³ã¹ã¿ã³ã¹ãå
±æããã(Singleton)ã¯ã©ã¹ã
ãããã¨ãå¤éç¶æ¿ãåºæ¥ãªãã®ã§ãã©ã¡ããã¯å®è£
ãæ¸ããä¾åæ§ã®æ³¨å
¥â»ã®å®è£
ãªã©å°ãã°ããé¢åãªãã¨ãããªããã°ãªãã¾ããã
â»ä¾åæ§ã®æ³¨å
¥(Dependency Injection) : ä»åã¯ç´¹ä»ãã¾ããããã¯ã©ã¹éã®ä¾åé¢ä¿ãçã«ããããã®ãã¶ã¤ã³ãã¿ã¼ã³ã®ä¸ã¤ã§ãã
ããã§åºã¦ããã®ã trait ã§ãã
trait ã¯ç¶æ¿ã¨ç°ãªããã¯ã©ã¹ã¨ã®éã«ç¸¦æ¹åã®é¢ä¿ãæ§ç¯ãã¾ããã
ãã®ä¾ãè¯ããæªããã¯ãã¦ããã trait ã®å ´åã¯ãã®ããã«æ¨ªæ¹åã«ãããã§ãã¯ã©ã¹ãæ¡å¼µãããã¨ãå¯è½ãªã®ã§ãã
å®è£ ã¯ã©ã¹ã«ãXXãè¡ãæ©è½ï¼æ¯ãèã(ã¡ã½ãããããããã£)ããå¤é¨å®è£ ã¨ãã¦è¿½å ãã¦ããã®ã trait ã¨ãªãã¾ãã
ã¤ã³ã¿ã¼ãã§ã¤ã¹ãç¨ããã°ãã(å¤é¨ããè¦ã¦)XXãåºæ¥ãã¯ã©ã¹ãã¨ããåãä½ããã¨ã¯åºæ¥ã¾ãã
ããããçµå±ãXXãåºæ¥ãã¯ã©ã¹ããå®è£ ããéã«ãæ¯åãã®ãXXãåºæ¥ããããã«ä¸èº«ãä½ããªããã°ãªãã¾ãã(ä¾ã¨ãã¦ãã¤ãã¬ã¼ã¿ã®å®è£ ãªã©)ã
ãããXXãåºæ¥ããã¨ããæ¯ãèããããç¨åº¦æ±ç¨åããã¦ãã¦ãè¤æ°ã®ç°ãªãã¯ã©ã¹ã«ããã¦ãã®æ¯ãèãã使ãããå ´åã¯ãåãå®è£ ãæµç¨ããããªãã¾ãããããªæã«ä½¿ããã®ããã® trait ã¨ãããã¨ã§ãã
â»ãä¸å®ã®æ¯ãèããã¢ã¸ã¥ã¼ã«åããã¯ã©ã¹ã«çµã¿è¾¼ããã¨ããæ¦å¿µã¯ãæ¢ã«ä»ã®è¨èªã§ãå®è£ ããã¦ãããã¨ãããã¾ãã
- Ruby ã® mix-in
- Scala ã® trait(è±)
- Perl6 ã® role(è±)
2. trait ã®å®è£ æ¹æ³ã¨å©ç¨æ¹æ³
ã©ããªæ㧠trait ãå®è£ ããã°ããã®ãã¨ç³ãã¾ãã¨ãã»ã¨ãã©ã®å ´åã«ããã¦
- ã©ã¤ãã©ãªã®å®è£
- ãã¬ã¼ã ã¯ã¼ã¯ã®å®è£
ã®ä¸é¨ã¨ãã¦ä½¿ãããã®ã§ã¯ãªããã¨æãã¾ãã
å®è£
ã®åå©ç¨ãç®çãªã®ã§ãåå©ç¨ãã¦ãããã©ã¤ãã©ãªããã¬ã¼ã ã¯ã¼ã¯ã«çµã¿è¾¼ã¿ãã¢ããªã±ã¼ã·ã§ã³ã¯ trait ãå©ç¨ã ããããã¨ããã¹ã¿ã¤ã«ã§ãããªã®ã§ trait ã®ç¥èã¯ãã¢ããªã±ã¼ã·ã§ã³éçºè
ãããã¬ã¼ã ã¯ã¼ã¯éçºè
ãç¥ãã¹ãã§ã¯ãªããã¨æãã¦ãã¾ã(ãã¡ãããã¢ããªã±ã¼ã·ã§ã³éçºè
ãããããã©ããã£ã¦å©ç¨ããããç¥ãå¿
è¦ã¯ããã¾ã)ã
trait èªä½ã®å®è£
ã¯ã¯ã©ã¹ã¨ã»ã¨ãã©åãæ¸ãæ¹ã§å¯è½ã§ãã
<?php trait SingletonTrait { private static $instance; private function __construct() { } public static function getInstance() { if (!isset(self::$instance)) { self::$instance = new self(); } return self::$instance; } }
ä½ããã¯ã©ã¹ãåºæ¥ã¦ trait ãåºæ¥ãªããã¨ãããã¾ãã
- trait èªä½ã®ã¤ã³ã¹ã¿ã³ã¹åã¯ä¸å¯è½(ã³ã³ã¹ãã©ã¯ã¿ã¯ããã)
- const ã«ããå®æ°å®£è¨ã¯ä¸å¯è½
- ã¯ã©ã¹ãç¶æ¿ããããã¤ã³ã¿ã¼ãã§ã¼ã¹å®è£ ã宣è¨åºæ¥ãªã(ã¯ã©ã¹ãããªãã®ã§)
ãã®æ¯ãèããå©ç¨ããã¯ã©ã¹å´ã®å®è£ ãç°¡åã§ãã
<?php class SomeManager { // ã·ã³ã°ã«ãã³ãã¿ã¼ã³ãå©ç¨ãã use SingletonTrait; public function processSomething() { // ... } } // ã¯ã©ã¹ã®å©ç¨ $mngr = SomeManager::getInstance(); $mngr->processSomething();
ãã®ããã«ãå®è£
ã¯ã©ã¹å´ã§æ©è½ãå®è£
ãã¦ããªãã¦ãã trait ã use ããã ãã§ä½¿ãã¾ãã
ã¾ããè¤æ°ã® trait ãå©ç¨ããéã trait å士ã§ã¡ã½ããåã被ã£ãå ´åãã insteadof, as ãªã©ã®ãã¼ã¯ã¼ãã使ããã¨ã§åé¿ãããã¨ãå¯è½ã§ãã
<?php class SomeClass { use SomeTrait, FooTrait { // $this->bar ã¡ã½ããã¯SomeTraitã®ãã®ã使ã SomeTrait::bar insteadof FooTrait; // $this->fooBar ã¡ã½ããã§FooTrait::barãå¼ã¶ FooTrait::bar as fooBar; }; public function someFunc() { // SomeTrait::barã¡ã½ãããå¼ã¶ $this->bar(); // FooTrait::barã¡ã½ãããå¼ã¶ $this->fooBar(); // å©ç¨å ã§ç´æ¥ trait ã®ã¡ã½ãããããããã£ãå¼ã³åºããã¨ã¯åºæ¥ãªã // SomeTrait::bar(); } }
â»ããããã£(ã¡ã³ãå¤æ°)ã®å®£è¨ã§ã¯ãååã®è¡çªã許ããã¦ãã¾ãããåãå¤ãåæåãã¦ã E_STRICT ã¨ã©ã¼ãåºã¾ãã
/* 使ãéãåãããªãã®ã§ãã */ trait ã¡ã½ããã®å¯è¦æ§(publicãªã©)ãå¤æ´ãããã¨ãå¯è½ã§ãã
trait SomeTrait { public function getPublicData() { // ... } } class SomeClass { use SomeTrait { SomeTrait::getPublicData as private; } } $c = new SomeClass; $c->getPublicData(); // PHP Fatal error: Call to private method SomeClass::getPublicData() from ...
3. ã©ã®ãããªã±ã¼ã¹ã§å®è£ ããã
å®è£
æ¹æ³ã»å©ç¨æ¹æ³ãããã£ãã¨ããã§ãå®éã©ã®ãããªæ㧠trait ãå®è£
ãã¹ãããã¨ããæãéè¦ã«ãªã£ã¦ããã¨æãã¾ãã
å
¨ã¦ã§ã¯ããã¾ããããç§ãæãã¤ããå®è£
ä¾ãããã¤ããç´¹ä»ãã¾ãã
3-a. ãã¶ã¤ã³ãã¿ã¼ã³ã®å®è£
ãã¶ã¤ã³ãã¿ã¼ã³ã¨ã¯ãä¸å®ã®æ³å(æ¯ãèã)ã«å¾ã£ã¦å®è£ ãããã¨ããææ³ã§ãã®ã§ããã®å®è£ ã« trait ãæ´»ç¨åºæ¥ã¾ãã
// Composite ãã¿ã¼ã³ trait Compositable { private $childs = []; public function addChild($child) { $this->childs[] = $child; } public function removeChild($child) { for ($i = 0; $i < count($this->childs); $i++) { if ($this->childs[$i] === $child) { unset($this->childs[$i]); break; } } } } // Template Method ãã¿ã¼ã³ // æ¯è¼çå¶ç´ã®å¤ãç¶æ¿ã®ä»£ããã« trait ãå©ç¨ããã trait Controller { protected function validateInput() { // ... } abstract protected function execute(); protected function printOutput() { // ... } public function process() { $this->validateInput(); $this->execute(); $this->printOutput(); // ... } }
3-b. interface ã®åºæ¬å®è£ ã¨ãã¦å®è£
å
±éæ©è½ã®åã宣è¨ãã interface ã§ãããåºæ¬çãªå®è£
ã¨ããã®ã¯ããç¨åº¦åãã§ãããã¨ãå¤ãã®ã§ã¯ãªãã§ããããã
ãããã£ãå ´åã¯ãç¶æ¿ã«ãã£ã¦å®è£
ãããããã trait ã使ã£ã¦å®è£
ããæ¹ãæ¡å¼µæ§ã«å¯ãã è¨è¨ã«ãªãå¾ã¾ãã
<?php // é£æ³é åã§ã¤ãã¬ã¼ãåºæ¥ããã¬ã¤ã trait HashIteratorTrait { private $it_pos = 0; // ãã¸ã·ã§ã³ private $it_now = ''; // ç¾å¨ãã¼ private $it_keys = []; // ãã¼é å private $it_data = []; // ã³ã³ãã³ã private function rewind() { $this->it_keys = array_keys($this->it_data); $this->it_pos = 0; $this->it_now = $this->it_keys[$this->it_pos]; } private function current() //... } class UserList implements Iterator { // Iterator ã¤ã³ã¿ã¼ãã§ã¤ã¹ããé£æ³é åã¤ãã¬ã¼ã¿ãã¨ãã¦å®è£ use HashIteratorTrait; public function __construct($user_id_list) { $list = []; foreach ($user_id_list as $user_id) { $list[$user_id] = new User($user_id); } $this->it_data = $list; } // ... } $user_list = new UserList([100, 101, 102, 103]); foreach ($user_list as $user_id => $user) { // ... }
3-c. ã¢ã¯ã»ãµã®å®è£
C# ã§ã¯ public int data { get; private set; } ãªã©ã¨ãã¦ç°¡åã«ãããããããã£ã¸ã®ã¢ã¯ã»ãµã§ãããPHPã§ã¯ä¸ã
é¢åã§ãã
trait ã§ãªã¼ãã¼ãã¼ãã¡ã½ãããå®è£
ãããã¨ã§ãç°¡åã«ã¢ã¯ã»ãµãå©ç¨åºæ¥ã¾ãã
<?php trait Accessor { private $properties = []; // ãªã¼ãã¼ã©ã¤ãããã°ã»ããå¯å¦ãå¤ãããã public function checkSet($name, $value) { return true; } public function __set($name, $value) { if ($this->checkSet($name, $value)) { $this->properties[$name] = $value; } } public function __get($name) { if (!isset($this->properties[$name])) { return null; } return $this->properties[$name]; } public function __isset($name) { return isset($this->properties[$name]); } public function __unset($name) { if (isset($this->properties[$name])) { unset($this->properties[$name]); } } }
ããã§ãç´¹ä»ãã以å¤ã«ããç¹å®ã®DIã³ã³ããè¦ç´ ã¸ã® getter ã¡ã½ããããSQLã¯ã¨ãªçæã®è£å©ãããªãã¼ã·ã§ã³ãªã©ãå¹ åºãè¦ç´ ã« trait ãæ´»ç¨åºæ¥ãã§ãããã
4. å®è£ æã®å°ãã¿
ç§ãå®éã« trait ãå®è£ ããéãå°ãæ°ã«ãªã£ããã¿ããç´¹ä»ãã¾ãã
4-a. ç¶æ¿ã¨ã®ä½µç¨
ãã¡ããã trait ã¯ç¶æ¿ã¨ä½µç¨ãããã¨ãå¯è½ã§ãã
<?php trait SomeTrait { public function someFunc() { echo "SomeTrait::someFunc\n"; } } abstract class FooBase { use SomeTrait; } class Bar extends FooBase { public function someFunc() { echo "Bar::someFunc\n"; parent::someFunc(); } }
親ã¯ã©ã¹ã§å©ç¨ããã trait ã¯ããã®è¦ªã¯ã©ã¹ã«å®è£ ããã¦ãããã®ã¨ãã¦ã¢ã¯ã»ã¹åºæ¥ã¾ãã
<?php $bar = new Bar; $bar->someFunc(); // 以ä¸ãåºåããã // Bar::someFunc // SomeTrait::someFunc
ç¶æ¿å
ã¯ã©ã¹ã§ parent ã§å¼ãã æã FooBase::someFunc ã¡ã½ããã¯å®è£
ããã¦ãã¾ããããããã« someTrait::someFunc ã¡ã½ãããè¦ã«è¡ã£ã¦ãããå¼ã³åºãã¾ãã
ä½ãã use ããã¯ã©ã¹ã§ trait ã®ã¡ã½ãããä¸æ¸ãããã¨ã as ãªã©ã使ããªã㨠trait å´ã®ã¡ã½ããã使ãã¾ããã®ã§æ³¨æã§ãã
class Foo { use SomeTrait { SomeTrait::someFunc as traitFunc; } public function someFunc() { // parent::someFunc() ã§ã¯å¼ã¹ãªã // SomeTrait::someFunc() ã¨ãå¼ã¹ãªã $this->traitFunc() // as ã§å¼ã¹ãããã«ãªã£ã } }
4-b. trait ãç¶æ (ããããã£)ãå©ç¨ããå ´å
ãã¡ãã trait ã¯ããããã£(ã¡ã³ãã¼å¤æ°)ãå®è£
ãããã¨ãå¯è½ã§ãã
ããããã¡ã½ããã¨éã£ã¦ããããã£ã®ååã®è¡çªã¯åé¿ããããã¨ãåºæ¥ã¾ããã
trait SomeTrait { public $property = 'Some'; } trait OtherTrait { public $property = 'Other'; } class TraitUser { use SomeTrait, OtherTrait; } // 以ä¸ã®ã¨ã©ã¼ãå®è¡æåºåããã // PHP Fatal error: SomeTrait and OtherTrait define the same property ($property) in the composition of TraitUser. However, the definition differs and is considered incompatible. Class was composed in /home/capiba-/test.php on line 13
trait ã¨å®è£
ã¯ã©ã¹ã§ã®ããããã£è¡çªãåæ§ã®ã¨ã©ã¼ãçºçãã¾ãã
trait å
ã®ã¿ã§ä½¿ãããããããã£ã«é¢ãã¦ã¯ããã¶ããªããã㪠prefix ãã¤ãããªã©ã§åé¡ç¡ãã¨æãã¾ãã
å®è£
ã¯ã©ã¹å´ã§è¨å®ãã¦æ¬²ããããããã£ã¯ã trait å´ã§å®£è¨ãã¦ãã¾ãã¨å®è£
ã¯ã©ã¹å´ã§å宣è¨åºæ¥ãªãã®ã§ã
- getter ã¡ã½ãããç¨æããã
- ããã¥ã¡ã³ããéã㦠const ãå®ç¾©ãã¦ããã£ãã
ããã®ããããã¨æãã¾ãã
trait FooTrait { // trait åã prefix ã«ãã¦å°ç¨ããããã£ã£ã½ããã private $foo_value = 'something'; // å®è£ ã¯ã©ã¹å´ã§å¤æ°ãè¨å®ãã¦æ¬²ããå ´å getter ãç¨æ abstract private function getBarValue(); public function getSomething() { // getter ããåå¾ $bar_value = $this->getBarValue(); // const ãå®ç¾©ãã¦ããã£ã¦åå¾ $class = get_called_class(); $baz_value = $class::BAZ_VALUE; // ... } }
é·ã ã¨æ¸ãã¦ãã¾ãã¾ããããæ¬æ¥ã¯ããã§ä»¥ä¸ã§ãããã®è¨äºããããªãã trait ã使ãã¯ãããéã®åèã«ãªãã°ã¨æãã¾ãã
åèã«ããã¦é ããè¨äº
ä»åã®è¨äºãä½æããã«ãããã以ä¸ã®è¨äºãåèã«ããã¦é ãã¾ããããããã¨ããããã¾ãã
è¥å¹²å
容ã¯ç°ãªãã¾ããã社å
åå¼·ä¼ã§å
¬éãããã¬ã¼ã³ã®è³æããã£ããã