ComBioLaw.De » Blog » เขียนโปรแกรม » Using Mix-ins with PHP

Using Mix-ins with PHP

imageแม้ว่า PHP จะเป็นภาษาเขียนโปรแกรมที่ได้รับความนิยมอย่างมาก ตามความนิยมในตัว Web Application แต่ก็มีความสามารถหลาย ๆ อย่างที่ผมคิดว่า PHP ควรมี แต่กลับไม่มี หนึ่งในนั้นคือ multi inheritance ซึ่งดูเหมือนจะเป็นแฟชั่นแบบหนึ่ง ที่ภาษาเขียนโปรแกรมหลาย ๆ ภาษาไม่สนับสนุน multi inheritance แต่แนะนำให้ใช้ interface แทน ซึ่งจริง ๆ แล้วมันใช้แทนกันได้ไม่ทั้งหมด โดยเฉพาะอย่างยิ่ง ในกรณีที่เราต้องการใช้ algorithm บางอย่างในตัว method การใช้ interface ไม่สามารถช่วยให้เรา reuse การใช้งาน method หรือ algorithm เหล่านี้ได้

ทางแก้ที่โปรแกรมเมอร์มืออาชีพเขาแนะนำกัน คือการใช้งาน Mix-ins แต่อย่าเพิ่งเข้าใจผิดนะครับ ว่า PHP สนับสนุน Mix-ins การใช้งาน Mix-ins ใน PHP ต้องมีการแฮกกันเล็กน้อยถึงจะสามารถใช้งานได้ ซึ่งต่างจาก Ruby หรือ Python การใช้งาน Mix-ins ที่ผมจะเขียนถึงนี้ ผมเอามาจากเวบของ Ivo Jansch อีกทีครับ

Mix-ins เป็นวิธีการยืม method ของคลาสอื่นมาใช้ ซึ่งต่างจาก multi inheritance ตรงที่คลาสที่ยืม กับคลาสที่ถูกยืม ไม่ได้มีความสัมพันธ์กับแบบ subclass - superclass ต่างจาก interface ตรงที่ interface กำหนดเพียงแค่ชื่อ method เท่านั้น ส่วนเนื้อใน method ก็ต้องไปกำหนดเองอีกที และต่างจาก method decoration ตรงที่ method decoration ไม่ต้องมีการสร้างคลาส โดยส่วนตัว ผมชอบ method decoration มากที่สุด แต่ PHP มันทำไม่ได้

แกนหลักของ Mix-ins ที่ผมจะเขียนถึงคือ การใช้ method ที่มีชื่อว่า __call ซึ่งทุกคลาสใน PHP จะมี method ชื่อนี้อยู่ ...

เขียนโปรแกรม เขียนโปรแกรม

bow_der_kleine bow_der_kleine

โดยเมโธท __call เป็นเมโธทประเภท "magic method intercepts" ซึ่งจะถูกเรียก เวลาที่เมโธทของออพเจคถูกเรียก แล้วเมโธทดังกล่าวไม่ได้มีอยู่จริง ซึ่งในกรณีของ Mix-ins นี้ เมโธทของคลาสที่ถูกยืมเมโธทจะถูกเรียกแทน ดังนั้น ปัญหาที่ว่า จะเรียกเมโธทไหนดี หากมีเมโธทที่มีชื่อซ้ำกัน ซึ่งอาจเกิดขึ้นได้ในกรณีของ multi inheritance ก็จะไม่เกิดขึ้นใน Mix-ins

ในการใช้งาน Mix-ins ในขั้นแรก เราต้องสร้างคลาสที่มีความสามารถในการยืมเมโธทขึ้นมาหนึ่งคลาสก่อน จากนั้นก็ให้คลาสอื่น ๆ ที่เราต้องการให้มีความสามารถในการยืมเมโธท inherit คลาสนี้อีกทีหนึ่ง ส่วนคลาสที่ถูกยืมเมโธท ไม่จำเป็นต้องมีความสามารถในการยืมเมโธท และไม่จำเป็นต้องรู้อะไรเกี่ยวกับ Mix-ins ซึ่งคลาสที่มีความสามารถในการยืมเมโธท จะมีหน้าตาประมาณนี้

<?php
/// @file
/// Generic base class for all objects that want to make use of
/// mixin functionality.
/// 
/// @author Ivo Jansch <http://www.jansch.nl/2006/08/23/mixins-in-php/>
 
//  bow_der_kleine : I guest, this class is a public domain.
 
/// Generic base class for all objects that want to make use of
/// mixin functionality
class Mixinable{
	var $mixinlookup = array();
 
	// The constructor takes a look at the mixins, and creates a lookup
	// array, so upon a method call, we can quickly determine whether the
	// method was mixed in.
	function mixinable(){
		if (is_array($this->mixins)){
			foreach($this->mixins as $mixin){
				$methods = get_class_methods($mixin);
				if (is_array($methods)){
					foreach($methods as $method){
						$this->mixinlookup[$method] = $mixin;
					}
				}
			}
		}
	}
 
	// The __call magic method intercepts any method that does not exist
	// and falls back to one of the mixins if they define the method that is
	// being called.
	function __call($method, $args){
		if (isset($this->mixinlookup[$method])){
			$elems = array();
			for ($i=0, $_i=count($args); $i<$_i; $i++){
				$elems[] = "$args[$i]";
			}
			eval("$result = ".$this->mixinlookup[$method]."::".$method."(".implode(',',$elems).");");
			return $result;
		}
		trigger_error('Call to undefined function '.$method, E_USER_WARNING);
	}
}
?>
plain code

หมายเหตุ คลาส Mixinable เดิมคือคลาส Object ของ Ivo Jansch ที่ผมนำมาปรับปรุงเพิ่มเติม

การใช้งาน Mixins ก็ง่าย ๆ ดังนี้ครับ

<?php
class Soldier{
	function coup(){
		echo("I can not coup, because I am a citizen.n");
	}
}
 
class Citizen{
	function elect(){
		echo("I am going to elect a delegate.n");
	}
}
 
class Person extends Mixinable{
	var $mixins = array("Citizen", "Soldier");
 
	function say(){
		echo("A person has the right to think and say.n");
	}
}
 
$person = new Person();
$person->say();
$person->elect();
$person->coup();
?>
plain code

โดยคลาส Person นั้น inherit ความสามารถการยืมเมโธทมาจากคลาส Mixinable และเดิมทีมีเพียงเมโธท say() เท่านั้น แต่ด้วยการ Mxinins หรือยืมเมโธทมาจาก Citizen และ Soldier ด้วยการกำหนด attribute ที่มีชื่อว่า $mixins ด้วยคำสั่ง

var $mixins = array("Citizen", "Soldier");
plain code

ทำให้ Person มีเมโธทอื่น ๆ อีกสองเมโธทนั่นคือ elect จาก Citizen และ coup จาก Soldier เพิ่มเติม จะเห็นได้ว่าการใช้งาน Mixins ช่วยให้เรา reuse การใช้งานเมโธทต่าง ๆ ได้ตามที่เราต้องการ

แม้กระนั้นก็ตามเมื่อเปรียบเทียบ Mix-ins กับ method decoration ผมคิดว่ายังมีความสามารถบางอย่างที่ Mix-ins ขาดไปได้แก่

  • คลาสที่ยืมเมโธท ต้องเป็น sublcass ของ Mixinable เสมอ หรือไม่อย่างนั้น ก็ต้องกำหนดความสามารถนี้เอาเอง
  • ไม่สามารถยืมเมโธทแบบ on the fly ได้ คือ สร้างออพเจคไปแล้ว มายืมเมโธททีหลัง
  • ไม่สามารถสร้างคลาสแบบ light weight ได้ คือตัวคลาสไม่ต้องมีความสามารถอะไรมาก แต่พออยากใช้งานอะไรก็มาเพิ่มเติมทีหลัง การใช้งาน Mix-ins เป็นการหนดความสามารถของคลาสไว้แล้วตั้งแต่ต้น
  • protected method ไม่สามารถถูกยืมมาใช้งานได้ (ไม่รู้จะเป็นข้อเสีย หรือข้อดี)
  • It's a hack.

แต่โดยรวมแล้ว ผมคิดว่า Mix-ins เป็นอะไรที่น่าสนใจไม่น้อย สำหรับการเขียนโปรแกรมด้วย PHP

21 Dec 08 | by | tags เขียนโปรแกรม PHP

read 1421

<<อัตรัฐ || 3G ละเมิดสิทธิบุคคล ?>>

บุญชิตฯ

ผมยังเขียนโปรแกรมแบบ Object ไม่เป็นเลยครับ คาดว่า มันคงซับซ้อนเกินไปสำหรับการศึกษาด้วยตนเอง

แต่เอาเฉพาะช่วงที่อ่านโค้ด php เข้าใจบ้าง และรู้สึกว่า ตัวอย่างเจ๋งดี :-D

23 Dec 08

bow_der_kleine

จริง ๆ OOP มันไม่ยากหรอกครับ ให้มองว่า Object คือ ตัวแปร array แบบนึงก็ไม่ผิดนัก (PHP มันมองอย่างนั้นจริง ๆ) แต่เป็นตัวแปร array ที่มีฟังก์ชันอยู่ข้างใน (method) สมาชิกใน array ก็คือ attribute นั่นเอง และ Class ก็เป็นแม่พิมพ์ ที่กำหนดพฤติกรรมของ Object

เรื่องตัวอย่าง ผมนึกว่าจะไม่มีใครสังเกตเสียแล้ว :D

23 Dec 08

ก้อนหินรูปหมู

Happy new year 2009 ค่ะ

ขอให้คุณ Charly, คุณเช, คุณbow มีความสุขมากๆตลอดไปค่ะ

 ขอบคุณที่เขียนบทความดีๆให้อ่านค่ะ (ชอบมาอ่านมากค่ะ)

 ^O^

26 Dec 08

ความคิดเห็น (click here to comment)

Search

Navigation

รวมลิงก์น่าสนใจ

ความเคลื่อนไหว

Login

name password

ลืมรหัสผ่าน