วันอังคารที่ 25 พฤศจิกายน พ.ศ. 2557

Object Oriented Programming


            ภาษาโปรแกรมสมัยใหม่ มักจะสนับสนุนหรือต้องการวิธีแบบ Object oriented programming เพื่อพัฒนาซอฟต์แวร์ ซึ่ง PHP สามารถพัฒนาโปรแกรมประยุกต์ประเภทนี้ได้
แนวคิด Object Oriented Programming
Object oriented programming (OOP) มีจุดสำคัญคือ ความสามารถสร้างประเภทข้อมูลใหม่ที่มีข้อมูลและการทำงานร่วมกัน การพัฒนาแบบนี้ใช้การจัดความสัมพันธ์และคุณสมบัติของอ๊อบเจคในระบบในปฏิบัติงาน Class และอ๊อบเจค  
       ในบริบทซอฟต์แวร์ OOP อ๊อบเจคสามารถเป็นสิ่งของหรือแนวคิดได้แก่ วัตถุทางกายภาค เช่น โต๊ะ ลูกค้า หรือวัตถุทางแนวคิดที่มีอยู่ในซอฟต์แวร์ เช่น พื้นที่ป้อนข้อความ ไฟล์ โดยทั่วไปความสนใจส่วนมากในวัตถุทางแนวคิด รวมถึงวัตถุในโลกจริงที่ต้องการนำเสนอในซอฟต์แวร์
       ซอฟต์แวร์ OOP เป็นชุดของอ๊อบเจคเก็บคุณลักษณะและปฏิบัติการ โดย คุณลักษณะคือ คุณสมบัติหรือตัวแปรที่สัมพันธ์กับอ๊อบเจค ปฏิบัติการคือ เมธอดการกระทำหรือฟังก์ชันที่อ๊อบเจคสามารถทำการปรับปรุงตัวเองหรือผลกระทบภายนอก  ซอฟต์แวร์แบบนี้ สนับสนุนและช่วยการห่อหุ้ม (encapsulation) ที่เรียกว่าการซ่อนข้อมูล ส่วนสำคัญคือ การเข้าถึงข้อมูลภายในอ๊อบเจคมีให้เฉพาะการผ่านปฏิบัติการของอ๊อบเจคที่เรียกว่าอินเตอร์เฟซของอ๊อบเจค
class แสดงแทนชุดของอ๊อบเจคที่อาจจะแปรผันจากแต่ละอ๊อบเจค แต่ต้องมีผลร่วมกัน ถึงแม้ว่าค่าของคุณลักษณะเหล่านั้นจะแปรผันตามอ๊อบเจค ตัวอย่าง จักรยาน สามารถคิดเป็น class ของอ๊อบเจคที่อธิบายจักรยานหลายประเภทด้วยส่วนการทำงานรวมหรือคุณลักษณะ เช่น 2 ล้อ สี ขนาด และปฏิบัติการ เช่น การเคลื่อนย้าย




Polymorphism  ภาษา Object oriented programming ต้องสนับสนุน polymorphism ซึ่งหมายความว่า แต่ละ class สามารถมีพฤติกรรมต่างสำหรับปฏิบัติการเดียวกัน เช่น มี class รถยนต์ และ class จักรยาน ทั้งคู่มีปฏิบัติการเคลื่อนย้ายต่างกัน วัตถุในโลกจริงมีปัญหาน้อย อย่างไรก็ตาม ภาษาโปรแกรมไม่คิดเหมือนโลกจริง ดังนั้นภาษาต้องสนับสนุน polymorphism เพื่อทราบถึงปฏิบัติการที่ใช้โดยอ๊อบเจคเฉพาะ
      
 polymorphism มีพฤติกรรมมากกว่าอ๊อบเจคใน PHP เฉพาะฟังก์ชันสมาชิกของ class สามารถเป็น polymorphism เปรียบเทียบกับโลกจริงคือ กริยาในภาษาธรรมชาติ ซึ่งเทียบเท่ากับฟังก์ชันสมาชิก พิจารณาการใช้จักรยานในชีวิตจริง คือ การทำความสะอาด การแยกชิ้น การซ่อม ทาสี เป็นต้น

การอินเฮอริต ยอมให้สร้างความสัมพันธ์ตามลำดับชั้น ระหว่าง class ด้วยการใช้ subclass โดย subclass ทำอินเฮอริต คุณลักษณะและปฏิบัติการจาก superclass  การอินเฮอริต ทำให้สามารถสร้างและเพิ่มไปยัง class ที่มีอยู่ จาก class ฐานอย่างง่าย สามารถทำได้มาจากให้ซับซ้อนมากขึ้นและเจาะจง class ตามความต้องการ สิ่งนี้ทำให้ใช้คำสั่งใหม่ได้ และเป็นข้อได้เปรียบสำคัญของ object oriented programming


การประยุกต์เบื้องต้น
การเรียนรู้โปรแกรมแบบ OOP เริ่มต้นจากการสร้างและทำงาน class ในฐานะอ๊อบเจคที่ประกอบด้วยคุณสมบัติ (หรือคุณลักษณะ) และปฏิบัติการ (หรือเมธอด)

Class
การประกาศ class ใช้คีย์เวิร์ด class รายละเอียดของ class ได้รับการหุ้มในวงเล็กปีกกา ({ })
<?php
class myclass
{
// รายละเอียด รวมถึง คุณสมบัติ และเมธอด เป็นต้น
}
?>
class นี้ให้ชื่อว่า myclass
class สร้างคุณลักษณะเป็นการประกาศตัวแปรภายในข้อกำหนด class ด้วยคีย์เวิร์ด var และการสร้างปฏิบัติการใช้การประกาศฟังก์ชัน
ตัวอย่างการสร้าง Employee class ที่ประกอบ 4 คุณลักษณะ ใน PHP สามารถสร้างค่าเริ่มต้นได้
<?php
class Employee
{
public $id;
public $firstname = “unknown”;
public $lastname;
public $sex = 1;
}
?>

Instance
การสร้างอ๊อบเจคที่ใช้ทำงานด้วยที่เรียกว่า instance ของอ๊อบเจค การสร้างใช้คีย์เวิร์ด new ต้องมีการระบุ class ที่อ๊อบเจคจะเป็น instance
<?php
$emp = new Employee();
?>
คุณลักษณะ
การเข้าถึงตัวแปรสมาชิกใช้ ชื่อ instance กับ -> operator ตามด้วยชื่อตัวแปรสมาชิก
<?php
$emp_name = $prod->firstname;
?>
ภายใน class การเข้าถึงตัวแปรสมาชิกใช้ -> operator และเข้าถึงด้วยพอยเตอร์พิเศษเรียกว่า $this
<?php
class Employee
{
public firstname;

// คำสั่งอื่น
$new_name = $this->firstname;
}
?>
การตั้งค่าให้กับตัวแปรสมาชิก
<?php
$emp->firstname = " อัศวิน ";
?>

เมธอด
ชื่อฟังก์ชันที่เป็นเมธอดต้องไม่ซ้ำกัน ตัวอย่างการสร้างเมธอดดูได้ฟังก์ชัน get_firstname() สำหรับการอ่านชื่อพนักงานและฟังก์ชัน set_firstname สำหรับการตั้งชื่อพนักงาน
    การเรียกเมธอดของ class เหมือนกับการเรียกคุณลักษณะของ class ถ้าเมธอดต้องการพารามิเตอร์ให้วางไว้ในวงเล็บ และระบุชื่อเจ้าของอ๊อบเจค
<?php
$new_emp = new Employee();
$first_name = $new_emp->get_firstname();
$new_emp-> set_firstname($new_name);
?>

การเริ่มต้นและทำความสะอาดอ๊อบเจค
เมื่อเริ่มต้นอ๊อบเจค Employee จากการสร้าง instance ของ Employee class สิ่งที่ลำบากคือการเริ่มค่า ตามตัวอย่างนี้
< ?php
$emp = new Employee();
$emp->id = "A321500"
$emp->name = " สุพจน์ ";
// และอื่นๆ ...
?>

การแก้ไขปัญหานี้ทำได้ด้วยแนวคิด constructor

Constructor
constructor เป็นวิธีการประมวลผลเมื่อ instance ใหม่ได้รับการสร้างขึ้น โดย constructor รับพารามิเตอร์ที่ส่งผ่าน new operator ด้วยการวางไว้ในวงเล็บหลังชื่อ class
<?php
class Employee
{
// ตัวแปรสมาชิก
public function __construct ($m_empid, $m_empfname, $m_emplname, $m_sex, $m_salary)
{
$this->id = $m_empid;
$this->firstname = $m_empfname;
$this->lastname = $m_emplname;
$this->salary = $m_salary;
$this->sex = $m_sex;
}
// คำสั่งอื่น
}
?>
การประกาศ constructor ให้กำหนดเป็น __construct ( เส้นใต้หรือ underscore 2 ตัวติดกัน) ถึงแม้ว่าสามารถเรียก constructor ได้เอง แต่วัตถุประสงค์หลักคือ การเรียกอย่างอัตโนมัติ เมื่ออ๊อบเจคได้รับการสร้างคำสั่งต่อไปประกาศ class ด้วย constructor

Destructor
เมธอด destructor ใช้ลบอ๊อบเจค การกำหนดใน PHP ผ่านฟังกชัน __destruct ถ้าไม่ได้กำหนดไว้ PHP จะดำเนินการทำความสะอาดและทำงานต่อ
<?php
// คำสั่งอื่น...
public function __destruct()
{
// วางคำสั่งทำความสะอาด
}
?>

Visibility
PHP ได้วิธีการควบคุมการดูหรือปรับปรุงข้อมูลกับตัวแปรสมาชิก รวมถึงการเรียกฟังก์ชันสมาชิก ทำให้กำหนดวิธีการดูข้อมูล การเก็บหรือแก้ไขข้อมูลได้ visibility มี 3 modifier คือ

public ทุกคนสามารถอ่านและปรับปรุงตัวแปรสมาชิกนี้ หรือเรียกเมธอดนี้ รวมทั้งสามารถใช้ได้โดยคำสั่งภายนอก คำสั่งภายใน class หรือ class ที่ขยายการทำงานกับ class ที่ระบุ
private เฉพาะคำสั่งภายใน class นี้สามารถอ่านหรือปรับปรุงตัวแปรสมาชิก private หรือเรียกฟังก์ชันสมาชิก private ส่วนคำสั่ง, class และ class ที่ขยายการทำงานกับ class นี้ไม่สามารถใช้รายการ private นี้ได้
protected คำสั่งภายนอกและ class อื่นที่ไม่มีความสัมพันธ์กับ class ที่กำหนดไม่สามารถอ่านและเขียนตัวแปรสมาชิก protected ได้ หรือเรียกฟังก์ชันสมาชิก protected แต่ class ที่ขยายการทำงานกับ class นี้ได้รับอนุญาตให้เข้าถึงหรือเรียกได้
ถ้าไม่ต้องการบุคคลอื่นแก้ไขข้อมูลให้เปลี่ยน visibility จาก public เป็น private หรือ protected แต่ให้คำสั่งภายนอกสามารถดูได้
<?php
class Employee
{
protected $id;
protected $firstname;
protected $lastname;
protected $sex;
protected $salary;
public function __construct ($m_empid, $m_empfname, $m_emplname, $m_sex, $m_salary)
{
$this->id = $m_empid;
$this->firstname = $m_empfname;
$this->lastname = $m_emplname;
$this->salary = $m_salary;
$this->sex = $m_sex;
}
public function __destruct()
{
// clean up
}
public function get_EmployeeID()
{
return $this->id;
}
public function get_EmployeeFullName()
{
return $this->firstname." ".$this->lastname;
}
//
// ฟังก์ชันอื่นๆ
//
public function get_EmployeeSex()
{
if ($this->sex == 1)
    return "Male";
else if ($this->sex == 2)
    return "Female";
else
    return "Unknow";
}
}
?>

ค่าคงที่และข้อมูลสถิตย์
ในบางกรณีอาจจะมีการกำหนดและใช้ค่าคงที่กับอ๊อบเจค ดังนั้นเรียนรู้วิธีการติดต่อกับค่าคงที่ ตัวแปรสถิตย์ (static variable) และเมธอดสถิตย์ (static method)
ค่าคงที่ของ Class
การกำหนดค่าคงที่ของ class
<?php
class Employee
{
const THAI = 1;
const FOREIGN = 2;

// คำสั่งอื่น...
}
?>
ค่าคงที่ไม่มีความสัมพันธ์กับอ๊อบเจค จึงไม่สามารถใช้ -> operator ได้ การเข้าถึงขึ้นกับแหล่งของค่าคงที่
  ภายนอก class การเข้าถึงค่าจากภายนอก class ให้ระบุเริ่มต้นชื่อ class ตามด้วย scope resolution operator ที่เป็น colon คู่ (::) และชื่อค่าคงที่
<?php
$emp = new Employee("321500", " สุพจน์" , " แสงไพบูลย์" , 1, 15000, Employee::THAI);
?>
  ภายใน class การเข้าถึงจากภายใน class ใช้คีย์เวิร์ด self เพื่อบอกให้ PHP มองหาใน class ปัจจุบันตามด้วย scope resolution operator และชื่อค่าคงที่
<?php
class Employee
{
// คำสั่งอื่น...
public function get_EmployeeNation()
{
if ($this->nation == self::THAI)
    return " ไทย" ;
else if ($this->nation == self::FOREIGN)
    return " ต่างชาติ" ;
else
    return "Unknow";
}
}
?>

ตัวแปรสมาชิกสถิตย์
ความต้องการข้อมูลบางอย่างสัมพันธ์กับทั้ง class ของอ๊อบเจค แต่ข้อมูลนี้ไม่ตายตัว ตัวแปรสมาชิกแบบนี้สามารถสร้างให้เป็น global กับทั้ง class แต่ไม่ใช่ instance ตัวแปรสมาชิกแบบนี้ PHP เรียกว่าตัวแปรสมาชิกสถิตย์ ( Static member variable) ประกาศด้วยคีย์เวิร์ด static
    การเข้าถึงตัวแปรสมาชิกสถิตย์เหมือนกับการเข้าถึงค่าคงที่จากภายใน class คือ ใช้คีย์เวิร์ด self ตามด้วย ด้วย scope resolution operator และชื่อตัวแปรสมาชิก
<?php
class Employee
{
private static $num_instance = 0;
public function __construct ($m_empid, $m_empfname, $m_emplname, $m_sex, $m_salary, $m_nation)
{
$this->id = $m_empid;
$this->firstname = $m_empfname;
$this->lastname = $m_emplname;
$this->salary = $m_salary;
$this->sex = $m_sex;
$this->nation = $m_nation;
self:: $num_instance++;
echo " การสร้าง instance จำนวน ".self:: $num_instance."<br/>\n";
}
}
?>
ตัวแปรสมาชิกสถิตย์สามารถกำหนดระดับ scope นอกจาก public และไม่ใช่อ่านอย่างเดียว ตัวแปรสมาชิกแบบนี้จะตั้งค่าใหม่ที่สคริปต์ประมวลผลใหม่ ในกรณีการนับตามตัวอย่างถ้าเป็นการเรียกคนละครั้งจะเป็น 1 แต่การป้อนต่อเนื่องโดยไม่ได้ออกจากสคริปต์จึงจะนับต่อเนื่องได้

เมธอดสถิตย์
ความต้องการปฏิบัติการกับระเภทงานที่ไม่จำเป็นต้องเจาะจง instance แต่ปฏิบัติงานตามประเภทงาน ตัวอย่าง ต้องการสร้างเมธอดบน Employee class ที่สร้างอ๊อบเจค Employee จำนวนหนึ่ง
การประกาศเมธอดใช้คีย์เวิร์ด static
<?php
class Employee
{
// คำสั่งอื่น...
public static function search_employee($search_value)
{
// คำสั่งค้นหา... กำหนดตาม $search_value
}
}
?>

การขยายอ๊อบเจค
Object oriented programming มีความสามารถในการห่อหุ้มข้อมูลเป็นประเภทข้อมูลใหม่ เมื่อมีการสร้าง Employee class ขึ้นมา ที่อินเฮอริตคุณสมบัติของพนักงานขึ้นมาได้

อินเฮอริต
ในทางปฏิบัติ ข้อมูลหลายประเภทอาจจะมีจำกัดขอบเขตผู้เข้าถึง เช่น ระบบจ่ายเงินเดือน ระบบโบนัส สิ่งเหล่านี้ไม่จำเป็นต้องเข้าสู่ระบบรวม แต่สามารถแบ่งส่วนออกมาได้  ถ้า class เป็น subclass ของอีก class สามารถใช้คีย์เวิร์ด extend เพื่อระบุการขยาย คำสั่งต่อไปนี้สร้าง Bonus class ที่อินเฮอริตจาก Employee class
<?php
class Bonus Extends Employee
{
protected static $bonus_rate = 1;
}
?>

การอินเฮอริตทำงานเพียง 1 ทิศทาง subclass หรือลูกอินเฮอริตส่วนการทำงานจากแม่หรือ class ฐาน แต่แม่ไม่สามารถใช้ส่วนการทำงานของลูก

Overriding
การให้ class ลูกสามารถปรับปรุงข้อมูลจากการ class ฐานหรือแม่ ตัวอย่าง Bonus class สามารถเพิ่มอัตราโบนัสเป็นพารามิเตอร์ PHP ยอมให้ทำได้และใช้ constructor จาก class ฐานด้วยการใช้คีย์เวิร์ด parent โดยรวมกับ scope resolution operator เพื่อเรียกเมธอดจาก class ฐาน วิธีนี้เรียกว่า Overriding เมธอดจาก class ฐาน ได้รับการแทนที่โดยเมธอดใหม่ของ class
<?php
class Bonus Extends Employee
{
protected $bonus_rate = 0.5;
public function __construct($m_empid, $m_empfname, $m_emplname, $m_sex, $m_salary, $m_nation, $m_bonus)
{
parent::__construct($m_empid, $m_empfname,
$m_emplname, $m_sex, $m_salary, $m_nation);
$this->bonus_rate = $m_bonus;
}
}
?>
เมธอด destructor ควรได้รับ overriding
<?php
public function __destruct()
{
// ควรเรียก destructor จากแม่
parent::__destruct();
}
?>
เมื่อ Bonus class ทำงานได้แล้ว ควรมีการปรับปรุงเมธอด get_EmployeePayroll() ใหม่ด้วยการ overriding จาก class ฐาน
<?php
public function get_EmployeePayroll()
{
return parent::get_EmployeeSalary()*(1+ $this->bonus_rate);
}
?>
การทำให้ Class ทำงานเหมือนกัน
หลักการสำคัญของ Object oriented programming ประการหนึ่งคือ ทำให้อินเตอร์เฟซเหมือนกันหรือ polymorphism ดังนั้นจึงต้องทำให้คำสั่งได้รับการเปลี่ยนแปลงนอกเหนือการควบคุม

โครงสร้างตามลำดับชั้นของ Class
โครงสร้างตามลำดับของสามารถขยายตามแนวดิ่งได้ด้วยอินเฮอริตได้ และสามารถปรับปรุงเมธอดจาก class ฐานด้วยการ overriding ได้สำหรับความเหมาะสมในการทำงาน ดังนั้นเมธอดบน class ฐานควรทำหน้าที่เป็นต้นแบบ (template) การกำหนดนี้ทำได้ด้วยการใช้คีย์เวิร์ด abstract

<?php
abstract class Employee
{
// คำสั่งอื่น...
}
?>

การป้องกันอินเฮอริตและ Overriding
บางเมธอดหรือ class อาจจะเกิดจากโครงสร้างตามลำดับชั้นของอ๊อบเจค ตัวอย่าง ป้องกันไม่ให้บุคคลทั่วไป overriding เมธอด get_EmployeeID ใน Employee class

การป้องกันใช้ คีย์เวิร์ด final
<?php
abstract class Employee
{
// คำสั่งอื่น...
final public function get_EmployeeID()
{
return $this->id;
}
}

?>

ไม่มีความคิดเห็น:

แสดงความคิดเห็น