สองเหตุผลหลักที่ต่อต้านการใช้วิธีการแบบคงที่คือ:
- รหัสโดยใช้วิธีการคงที่ยากที่จะทดสอบ
- รหัสโดยใช้วิธีการคงที่เป็นการยากที่จะขยาย
การมีวิธีการแบบสแตติกเรียกใช้ในวิธีอื่นนั้นจริง ๆ แล้วแย่กว่าการนำเข้าตัวแปรส่วนกลาง ใน PHP คลาสเป็นสัญลักษณ์สากลดังนั้นทุกครั้งที่คุณเรียกใช้เมธอดสแตติกคุณต้องพึ่งพาสัญลักษณ์สากล (ชื่อคลาส) นี่เป็นกรณีที่โลกกำลังชั่วร้าย ฉันมีปัญหากับวิธีการนี้กับส่วนประกอบบางส่วนของ Zend Framework มีคลาสที่ใช้การเรียกเมธอดแบบคงที่ (โรงงาน) เพื่อสร้างวัตถุ เป็นไปไม่ได้ที่ฉันจะจัดหาโรงงานอื่นให้กับอินสแตนซ์นั้นเพื่อให้ได้รับวัตถุแบบกำหนดเองคืนมา การแก้ปัญหานี้คือการใช้อินสแตนซ์และวิธีการอินสแตนซ์เท่านั้นและบังคับใช้ซิงเกิลตันและไลค์ในตอนเริ่มต้นของโปรแกรม
Miško Heveryผู้ทำงานในฐานะ Agile Coach ที่ Google มีทฤษฎีที่น่าสนใจหรือแนะนำว่าเราควรแยกเวลาการสร้างวัตถุออกจากเวลาที่เราใช้วัตถุนั้น ดังนั้นวงจรชีวิตของโปรแกรมจะแบ่งออกเป็นสอง ส่วนแรก ( main()
วิธีที่เราจะพูด) ซึ่งดูแลการเดินสายวัตถุทั้งหมดในแอปพลิเคชันของคุณและส่วนที่ใช้งานได้จริง
ดังนั้นแทนที่จะมี:
class HttpClient
{
public function request()
{
return HttpResponse::build();
}
}
เราควรทำ:
class HttpClient
{
private $httpResponseFactory;
public function __construct($httpResponseFactory)
{
$this->httpResponseFactory = $httpResponseFactory;
}
public function request()
{
return $this->httpResponseFactory->build();
}
}
จากนั้นในหน้าดัชนี / หลักเราจะทำ (นี่คือขั้นตอนการเดินสายวัตถุหรือเวลาในการสร้างกราฟของอินสแตนซ์ที่โปรแกรมจะใช้):
$httpResponseFactory = new HttpResponseFactory;
$httpClient = new HttpClient($httpResponseFactory);
$httpResponse = $httpClient->request();
แนวคิดหลักคือการแยกการพึ่งพาจากชั้นเรียนของคุณ วิธีนี้โค้ดสามารถขยายได้มากขึ้นและส่วนที่สำคัญที่สุดสำหรับฉันสามารถทดสอบได้ ทำไมการทดสอบจึงสำคัญกว่า เนื่องจากฉันไม่ได้เขียนรหัสห้องสมุดเสมอไปดังนั้นความสามารถในการขยายจึงไม่สำคัญ แต่ความสามารถในการทดสอบมีความสำคัญเมื่อฉันทำการปรับโครงสร้างใหม่ อย่างไรก็ตามรหัสที่ทดสอบได้มักจะให้รหัสที่ขยายได้ดังนั้นจึงไม่ใช่สถานการณ์จริงหรืออย่างใดอย่างหนึ่ง
Miško Hevery ยังสร้างความแตกต่างที่ชัดเจนระหว่างซิงเกิลและซิงเกิล (ที่มีหรือไม่มีทุน S) ความแตกต่างนั้นง่ายมาก ซิงเกิลที่มีตัวพิมพ์เล็ก "s" ถูกบังคับใช้โดยการเดินสายในดัชนี / main คุณสร้างอินสแตนซ์ของคลาสที่ไม่ใช้รูปแบบซิงเกิลและดูแลว่าคุณส่งอินสแตนซ์นั้นไปยังอินสแตนซ์อื่นที่ต้องการเท่านั้น ในทางกลับกันซิงเกิลที่มีตัวอักษร "S" เป็นการนำรูปแบบคลาสสิก (ต่อต้าน -) โดยทั่วไปทั่วโลกในการปลอมตัวซึ่งไม่ได้ใช้มากในโลก PHP ฉันยังไม่เห็นจุดใดจุดหนึ่ง ถ้าคุณต้องการให้การเชื่อมต่อฐานข้อมูลเดียวใช้โดยคลาสทั้งหมดของคุณจะดีกว่าที่จะทำเช่นนี้
$db = new DbConnection;
$users = new UserCollection($db);
$posts = new PostCollection($db);
$comments = new CommentsCollection($db);
โดยการทำข้างต้นเป็นที่ชัดเจนว่าเรามีซิงเกิลตันและเรามีวิธีที่ดีในการฉีดจำลองหรือต้นขั้วในการทดสอบของเรา มันน่าประหลาดใจที่การทดสอบหน่วยนำไปสู่การออกแบบที่ดีขึ้น แต่มันสมเหตุสมผลดีเมื่อคุณคิดว่าการทดสอบบังคับให้คุณคิดเกี่ยวกับวิธีที่คุณใช้รหัสนั้น
/**
* An example of a test using PHPUnit. The point is to see how easy it is to
* pass the UserCollection constructor an alternative implementation of
* DbCollection.
*/
class UserCollection extends PHPUnit_Framework_TestCase
{
public function testGetAllComments()
{
$mockedMethods = array('query');
$dbMock = $this->getMock('DbConnection', $mockedMethods);
$dbMock->expects($this->any())
->method('query')
->will($this->returnValue(array('John', 'George')));
$userCollection = new UserCollection($dbMock);
$allUsers = $userCollection->getAll();
$this->assertEquals(array('John', 'George'), $allUsers);
}
}
สถานการณ์เดียวที่ฉันใช้ (และฉันใช้เพื่อเลียนแบบวัตถุต้นแบบ JavaScript ใน PHP 5.3) สมาชิกแบบคงที่คือเมื่อฉันรู้ว่าฟิลด์ที่เกี่ยวข้องจะมีค่าข้ามอินสแตนซ์เดียวกัน ณ จุดนี้คุณสามารถใช้คุณสมบัติคงที่และอาจเป็นวิธีการ getter / setter คู่คงที่ อย่างไรก็ตามอย่าลืมเพิ่มความเป็นไปได้สำหรับการแทนที่สมาชิกแบบคงที่ด้วยสมาชิกอินสแตนซ์ ยกตัวอย่างเช่น Zend Framework ถูกใช้คุณสมบัติคงที่เพื่อที่จะระบุชื่อของคลาสอะแดปเตอร์ DB Zend_Db_Table
ที่ใช้ในกรณีของ มันใช้เวลาไม่นานเพราะฉันใช้มันดังนั้นมันอาจจะไม่เกี่ยวข้องอีกต่อไป แต่นั่นเป็นวิธีที่ฉันจำได้
วิธีสแตติกที่ไม่ได้จัดการกับคุณสมบัติสแตติกควรเป็นฟังก์ชัน PHP มีฟังก์ชั่นและเราควรใช้มัน