ฉันสังเกตเห็นว่าใน PHP5 มีการเพิ่มส่วนต่อประสานกับภาษา อย่างไรก็ตามเนื่องจาก PHP ถูกพิมพ์อย่างหลวม ๆ ดูเหมือนว่าประโยชน์ส่วนใหญ่ของการใช้ส่วนต่อประสานจะหายไป ทำไมสิ่งนี้จึงรวมอยู่ในภาษา
ฉันสังเกตเห็นว่าใน PHP5 มีการเพิ่มส่วนต่อประสานกับภาษา อย่างไรก็ตามเนื่องจาก PHP ถูกพิมพ์อย่างหลวม ๆ ดูเหมือนว่าประโยชน์ส่วนใหญ่ของการใช้ส่วนต่อประสานจะหายไป ทำไมสิ่งนี้จึงรวมอยู่ในภาษา
คำตอบ:
ข้อได้เปรียบหลักของอินเทอร์เฟซใน PHP คือคลาสสามารถใช้หลายอินเตอร์เฟสได้ สิ่งนี้ช่วยให้คุณสามารถจัดกลุ่มคลาสที่ใช้งานได้บางอย่าง แต่ไม่จำเป็นต้องแชร์คลาสพาเรนต์ ตัวอย่างบางตัวอย่างอาจรวมถึงการแคชเอาต์พุตหรือการเข้าถึงคุณสมบัติของคลาสด้วยวิธีการบางอย่าง
ในรหัสของคุณคุณสามารถตรวจสอบว่าคลาสใช้อินเทอร์เฟซที่กำหนดแทนการตรวจสอบชื่อคลาส จากนั้นรหัสของคุณจะยังคงทำงานเมื่อมีการเพิ่มคลาสใหม่
PHP มีอินเตอร์เฟซที่กำหนดไว้ล่วงหน้าบางอย่างที่อาจเข้ามามีประโยชน์ในสถานการณ์ต่างๆ: http://php.net/manual/en/reserved.interfaces.php
แก้ไข - การเพิ่มตัวอย่าง
หากคุณมีอินเทอร์เฟซชื่อ MyInterface และคุณกำลังทำงานกับวัตถุหลายคลาสที่แตกต่างกันซึ่งอาจจะใช่หรือไม่ใช้ฟังก์ชั่นบางอย่างอินเทอร์เฟซอนุญาตให้คุณทำสิ่งนี้:
// Assume $objects is an array of instances of various classes
foreach($objects as $obj) {
if($obj instanceof MyInterface) {
$obj->a();
$obj->b();
$obj->c();
}
}
PHP ถูกพิมพ์อย่างหลวม ๆ แต่ก็สามารถพิมพ์ได้อย่างมากเกี่ยวกับสิ่งต่าง ๆ เช่นพารามิเตอร์วิธีการ
ลองพิจารณาตัวอย่างต่อไปนี้:
interface Car { function go(); }
class Porsche { function go() {} }
function drive(Car $car) {}
$porsche = new Porsche();
drive($porsche);
รหัสข้างต้นจะส่งออก:
อาร์กิวเมนต์ 1 ที่ส่งไปยังไดรฟ์ () จะต้องใช้ส่วนต่อประสานกับรถยนต์เช่นของปอร์เช่ที่ให้ไว้
null
ค่าเริ่มต้นสำหรับพารามิเตอร์ได้
drive
ต้องการ a Car
, การส่งผ่านnull
จะไม่มีประโยชน์มากเลย ...
function addView($name, Template $template, SecurityMode $securityMode = null, $methodName = null);
คุณอาจมีแต่ไม่มี$methodName
$securityMode
อินเทอร์เฟซช่วยให้คุณสามารถใช้หลักการเปิด - ปิดรักษาฐานรหัสคู่อย่างหลวม ๆ และใช้รูปแบบการออกแบบ OOP ที่ดีที่สุด
ตัวอย่างเช่นหากคลาสหนึ่งยอมรับคลาสอื่นเป็นอาร์กิวเมนต์:
class A {
public function __construct(B $class_b) {
// use class b
$class_b->run();
}
}
คลาส A และคลาส B ของคุณมีข้อต่อแน่นหนาและคลาส A ไม่สามารถใช้คลาสอื่นได้ยกเว้น B การบอกกล่าวชนิดทำให้แน่ใจว่าคุณมีอาร์กิวเมนต์ที่ถูกต้อง แต่ตอนนี้ได้เชื่อมความสัมพันธ์ระหว่าง A และ B เรียบร้อยแล้ว
ให้บอกว่าคุณต้องการให้คลาส A สามารถใช้คลาสทุกประเภทที่มีเมธอด run () ได้ นี่คือรูปแบบการออกแบบ COMMAND (แต่ไม่มาก) เพื่อแก้ปัญหาคุณต้องพิมพ์คำใบ้โดยใช้ส่วนต่อประสานแทนคลาสที่เป็นรูปธรรม B จะใช้อินเตอร์เฟสนั้นและจะได้รับการยอมรับว่าเป็นอาร์กิวเมนต์สำหรับคลาส A ด้วยวิธีนี้คลาส A สามารถยอมรับคลาสใด ๆ ที่ใช้อินเทอร์เฟซนั้นเป็นอาร์กิวเมนต์สำหรับตัวสร้าง
การเข้ารหัสประเภทนี้ใช้ในรูปแบบการออกแบบส่วนใหญ่ของ OOP และช่วยให้สามารถเปลี่ยนแปลงรหัสได้ง่ายขึ้นในเวลาต่อมา เหล่านี้เป็นส่วนหนึ่งของพื้นฐานของการเขียนโปรแกรม Agile
@pjskeptic มีคำตอบที่ดีและ @Kamil Tomšíkมีความเห็นที่ดีเกี่ยวกับคำตอบนั้น
สิ่งที่ยอดเยี่ยมเกี่ยวกับภาษาที่พิมพ์แบบไดนามิกเช่น PHP คือคุณสามารถลองใช้วิธีการกับวัตถุและมันจะไม่ส่งเสียงกรี๊ดใส่คุณยกเว้นว่าไม่มีวิธีดังกล่าวอยู่ที่นั่น
ปัญหาเกี่ยวกับภาษาที่พิมพ์แบบไดนามิกเช่น PHP คือคุณสามารถลองใช้วิธีการกับวัตถุและมันจะส่งเสียงกรี๊ดถึงคุณเมื่อไม่มีวิธีดังกล่าว
อินเทอร์เฟซเพิ่มวิธีที่สะดวกในการเรียกใช้เมธอดบนวัตถุที่ไม่รู้จักและมั่นใจว่าวิธีการนั้นมีอยู่ (ไม่ใช่ว่าพวกเขาจำเป็นต้องถูกต้องหรือไปทำงาน) มันไม่ใช่ส่วนที่จำเป็นของภาษา แต่มันทำให้การเขียนโค้ดสะดวกยิ่งขึ้น อนุญาตให้นักพัฒนา OOP ที่พิมพ์อย่างยิ่งสามารถเขียนโค้ด PHP ที่พิมพ์ได้อย่างรุนแรงซึ่งสามารถทำงานร่วมกับโค้ด PHP ที่พิมพ์โดยนักพัฒนา PHP คนอื่นได้
ฟังก์ชั่นเช่น:
foo( IBar $bar )
{
$baz = $bar->baz();
...
}
สะดวกกว่า:
foo( $bar )
{
if ( method_exists( $bar, 'baz' ) )
{
$baz = $bar->baz();
}
else
{
throw new Exception('OMGWTF NO BAZ IN BAR!');
}
...
}
และ IMHO รหัสที่อ่านง่ายคือรหัสที่ดีกว่า
พวกมันไร้ประโยชน์อย่างสมบูรณ์หากคุณเป็นคนที่ชอบจับจองจริง ๆ แล้วตอนที่คุณพิมพ์เป็ดมันค่อนข้างน่ารำคาญที่จะทำงานกับห้องสมุด / กรอบงานที่ใช้คำใบ้แบบไหนก็ได้
สิ่งนี้ใช้ได้กับการเขียนโปรแกรมเมตาแบบไดนามิกทุกประเภท (วิธีการทางเวทมนตร์)
PHP เป็นไม่หลวมหรือขอ แต่พิมพ์แบบไดนามิก
เกี่ยวกับอินเทอร์เฟซสิ่งแรกที่คุณควรถามตัวเองคืออะไรคือประโยชน์สูงสุดของอินเทอร์เฟซ
ใน OOP อินเทอร์เฟซไม่เพียง แต่เกี่ยวกับประเภท แต่เกี่ยวกับพฤติกรรมเช่นกัน
เนื่องจาก PHP ยังมีคุณสมบัติคำใบ้ประเภทคุณสามารถใช้อินเทอร์เฟซเช่นเดียวกับในภาษา oo เช่น Java
interface File
{
public function getLines();
}
CSVFile implements File
{
public function getLines()
{}
}
XMLFile implements File
{
public function getLines()
{}
}
JSONFile implements File
{
public function getLines()
{}
}
class FileReader
{
public function read(File $file)
{
foreach($file->getLines() as $line)
{
// do something
}
}
}
ด้วยการใช้อินเทอร์เฟซ PHP คุณสามารถสร้าง mocks สำหรับคลาสนามธรรมโดยใช้PHPUnitและนี่คือคุณสมบัติที่ยอดเยี่ยม:
public function testSomething()
{
$mock = $this->getMockForAbstractClass('File');
$mock->expects($this->once())
->method('getLines')
->will($this->returnValue(array()));
// do your assertions
}
ดังนั้นโดยทั่วไปคุณสามารถมีแอพพลิเคชั่นที่เข้ากันได้กับโซลิดใน PHP โดยใช้คุณสมบัติภาษาหนึ่งในนั้นคืออินเทอร์เฟซ
อินเทอร์เฟซมีประโยชน์สำหรับการฉีดพึ่งพามากขึ้นกว่าคอนกรีต เป็นตัวอย่างของแบร์โบน:
interface Istore {
public function save();
}
class Article_DB implements Istore
{
public function save($data)
{
// do save to format needed.
}
}
class Article
{
private $content;
public function content($content)
{
$this->content = $content;
}
public function save(Istore $store)
{
$store->save($this->content);
}
}
$article = new Article();
$article->content('Some content');
$store = new Article_DB();
$article->save($store);
ตอนนี้ถ้าความต้องการของคุณเปลี่ยนไปและคุณต้องการบันทึกเป็น pdf คุณสามารถสร้างคลาสใหม่เพื่อจุดประสงค์นั้นแทนการสร้างมลภาวะให้กับคลาสบทความ
class Article_PDF implements Istore
{
public function save($data)
{
// do save to format needed.
}
}
$article = new Article();
$article->content('Some content');
$store = new Article_PDF();
$article->save($store);
ตอนนี้คลาสของบทความมีสัญญาที่คลาสที่ใช้ในการบันทึกต้องใช้อินเทอร์เฟซ Istore มันไม่สนใจว่ามันจะถูกบันทึกไว้ที่ไหนหรืออย่างไร
คุณสามารถให้วัตถุจริง "ปลอม" ที่ใช้อินเทอร์เฟซ จากนั้นคุณสามารถทดสอบหน่วยของคุณโดยไม่ต้องใช้เซิร์ฟเวอร์ระบบไฟล์ซ็อกเก็ตฐานข้อมูลเป็นต้น
ผู้คนจำนวนมากอาจจะเกลียดฉันที่ตอบแบบนี้ แต่วิธีแก้ไขปัญหาการพิมพ์ของคุณสามารถแก้ไขได้อย่างง่ายดายด้วย PHP ใช่ PHP ถูกพิมพ์อย่างหลวม ๆ ดังนั้นประเภทจะถือว่าเป็นค่าเริ่มต้นซึ่งอาจทำให้เกิดปัญหาบางอย่างโดยเฉพาะอย่างยิ่งในการดำเนินการเปรียบเทียบซึ่งเป็นปัญหาของคนส่วนใหญ่กับมัน ที่ถูกกล่าวว่า, PHP สามารถเข้มงวดเช่นเดียวกับภาษาที่พิมพ์อย่างยิ่งถ้าคุณใช้สิ่งที่คุณใช้เป็นประเภทที่คุณต้องการและจากนั้นใช้ตัวดำเนินการเปรียบเทียบระดับบิต นี่คือตัวอย่างที่ง่ายที่สุดที่ฉันสามารถนึกถึงสิ่งที่ฉันพูด:
$ myVar = (int) 0; $ myOtherVar = '0';
การเปรียบเทียบ ($ myVar == $ myVar) จะเท่ากัน (บูล) จริง
แต่การเปรียบเทียบ ($ myVar === $ myVar) จะเท่ากับ (บูล) false เหมือนการเปรียบเทียบแบบ "พิมพ์" ใด ๆ
ฉันแค่หวังว่านักพัฒนาจะหยุดโต้เถียงเกี่ยวกับสิ่งเหล่านี้ถ้าคุณมีปัญหากับวิธีการทำงานของ PHP ในโปรแกรมจาวาและใช้งานแบบสดและปล่อยให้เป็นแบบสดหรือใช้แบบที่มันจะทำในสิ่งที่คุณต้องการ .. คุณรู้สึกดีกับมันอย่างไร? ให้ข้ออ้างที่จะพลาดทุกวันไหม? ทำให้คุณดูดีกว่าคนอื่นใช่ไหม เป็นเรื่องที่ดีมากที่คุณรู้สึกดีกับตัวเองมากจนคุณเต็มใจที่จะทำให้คนอื่นดูไม่ดี แต่ในความเป็นจริงแล้วมันเป็นสิ่งที่คุณชอบและบังคับให้ความเชื่อของคุณกับใครก็ตามจริงๆแค่ทำให้พวกเขาเขียนโค้ด
1) พวกเขาจะเขียนโค้ดในแบบของคุณ แต่ "ยุ่งเหยิง" ตามมาตรฐานของคุณ (คิดว่าคุณเคยเห็นโปรแกรมเมอร์ Java สร้างโปรแกรม PHP ตัวแรกหรือในทางกลับกันมันจะเป็นวิธีเดียวกับที่เปลี่ยนวิธีการหรืออาจแย่กว่าเดิม)
2) คุณจะพบสิ่งอื่นที่คร่ำครวญ
3) มันอาจจะใช้เวลานานกว่านั้นสำหรับพวกเขาในการผลิต และบางทีมันอาจจะทำให้คุณดูดีขึ้นในระยะสั้น แต่ทีมโดยรวมจะดูแย่ลงสำหรับมัน (โปรดจำไว้ว่าคุณอาจเขียนโค้ดช้ากว่าคนอื่นและนั่นก็ไม่ได้เลวร้ายเสมอไปถ้าทีมพบกับการส่งมอบในระยะเวลาที่เหมาะสม แต่การบังคับให้นิสัยของคุณกับคนที่ทำงานเร็วกว่าปกติอาจทำให้ทีมงานของคุณช้าลงดังนั้นดูแย่ลงในขั้นตอนการทำงานที่ต้องการมาก)
ฉันเองชอบเขียนโค้ด PHP ขั้นตอนแม้ว่าฉันจะสามารถและมีเขียนโปรแกรมเต็มรูปแบบโดยใช้ OOP ในภาษาที่แตกต่างกันไม่กี่ ที่ถูกกล่าวว่าฉันได้เห็นรหัส OOP ที่ดีและรหัส OOP ที่ไม่ดีและรหัสขั้นตอนที่ดีและรหัสขั้นตอนที่ไม่ดีสำหรับเรื่องนั้น ... มันไม่มีอะไรเกี่ยวข้องกับการฝึกซ้อม แต่ด้วยนิสัยที่คุณใช้และแม้กระทั่งแล้ว หลายสิ่งหลายอย่างเป็นความรู้สึกตีความของฉัน ... นั่นไม่ได้หมายความว่าฉันจะพูดไม่ดีเกี่ยวกับนักพัฒนาเหล่านั้นหรือบอกว่าคุยโม้ด้วย "วิธีของฉันดีที่สุด" BS มันเหมาะสำหรับฉันและ บริษัท ที่ฉันทำงานเพื่อจะสวย มีความสุขกับงานของฉันและฉันภูมิใจในสิ่งนั้น มีเหตุผลควรสร้างมาตรฐาน แต่สิ่งที่คุณรวมไว้ในมาตรฐานที่คุณเลือกมีความสำคัญมาก ... ขอบคุณที่ให้ฉันถอดมันออกจากอก ขอให้มีความสุขมาก ๆ ในวันนี้นะ
ตัวอย่าง: คุณต้องแคชข้อมูลของคุณ อย่างไร? มีเอ็นจินต่าง ๆ มากมายสำหรับการแคชซึ่งอันไหนดีที่สุด? ใครสนใจถ้าคุณมีเลเยอร์นามธรรมซึ่งมีอินเทอร์เฟซ ICacheDriver กับชุดของวิธีการเช่นคีย์, รับ, วาง, ล้าง, ฯลฯ เพียงแค่นำไปใช้กับสิ่งที่คุณต้องการในโครงการปัจจุบันและเปลี่ยนเมื่อคุณต้องการอีก หรือใช้งานง่าย ๆ ของ toString คุณมีชุดของวัตถุที่แสดงได้ที่แตกต่างกัน คุณเพิ่งใช้ส่วนต่อประสานแบบ Stringable (ซึ่งอธิบายถึงวิธี toString [ไม่มีอินเทอร์เฟซแบบนั้นใน PHP แต่เป็นตัวอย่าง]) และแค่สอดแทรกออบเจ็กต์ทั้งหมดของคุณด้วย (string) $ obj มีสิ่งที่คุณต้องทำแทนสวิตช์ (จริง) {case $ obj isntanceof A1: "do 1"; ทำลาย; ... }
ง่าย ดังนั้นจึงไม่มีคำถาม "ทำไม" มี "วิธีการใช้ที่ดีกว่า" ;-) โชคดี.
ฉันเดา
PHP ถูกใช้โดยโปรแกรมเมอร์ระดับเริ่มต้นจำนวนมากโปรแกรมเมอร์ระดับเริ่มต้นได้รับการสอนภาษาจาวาในวิทยาลัย
หลังจากหลักสูตรการเขียนโปรแกรม 101 พวกเขาเริ่มจู้จี้ Zend พวกเขาต้องการฟีเจอร์จาวาเพราะนั่นคือวิธีที่พวกเขาได้รับการสอนให้คิดคิดในแง่ของคุณเอง (หรือเข้าใจการพิมพ์เป็ด) มันยากเมื่อคุณอายุเพียง 20 ปี
Zend สามารถใช้งานได้ง่ายกว่าการเพิ่มคุณสมบัติอื่น ๆ
นอกจากนี้ยังซื้อผู้ใช้เพิ่มเติมแทนที่จะทำให้พวกเขาออกไปดังนั้นมันจะต้องดี
อีกตัวอย่างของกระบวนการนี้? คนออกใหม่ของ NET และหลักสูตร Java ยังต้องการกรอบของการเรียนมูลนิธิพวกเขาจู้จี้กับมันจนกว่า Zend ถั่วงอกออกZend Framework สิ่งนี้ซื้อในผู้ใช้มากขึ้น และในและใน ...
(คุณลักษณะภาษาเพียงทีมที่ PHP เป็นที่รู้จักกันว่าจะมีการต่อสู้กับในช่วงหลายปีที่เป็นgoto
)
PHP12
อาจจะมีคุณสมบัติทั้งหมดไวยากรณ์ของโลก (ผมหวังว่ามันจะไม่ได้รับการรันไทม์ชั้น abstraction, ยาก, เป็นที่สิ่งที่ฆ่า Perl) goto
ขยิบตาให้กับการทำงานและกระบวนทัศน์ประเภทข้อมูลและยังคงไม่มี