स्थैतिक तरीकों का उपयोग करने के खिलाफ मुख्य दो कारण हैं:
- स्थिर तरीकों का उपयोग करके कोड का परीक्षण करना कठिन है
- स्थिर तरीकों का उपयोग करके कोड का विस्तार करना मुश्किल है
किसी अन्य विधि के अंदर एक स्थिर विधि कॉल होना वास्तव में एक वैश्विक चर आयात करने से भी बदतर है। PHP में, कक्षाएं वैश्विक प्रतीक हैं, इसलिए हर बार जब आप एक स्थिर विधि कहते हैं तो आप एक वैश्विक प्रतीक (वर्ग नाम) पर भरोसा करते हैं। यह एक ऐसा मामला है जब वैश्विक बुराई है। मुझे Zend फ्रेमवर्क के कुछ घटक के साथ इस तरह के दृष्टिकोण की समस्या थी। ऐसी कक्षाएं हैं जो वस्तुओं के निर्माण के लिए स्थैतिक विधि कॉल (कारखानों) का उपयोग करती हैं। एक कस्टमाइज़्ड ऑब्जेक्ट को वापस पाने के लिए उस उदाहरण के लिए किसी अन्य कारखाने की आपूर्ति करना मेरे लिए असंभव था। इस समस्या का हल केवल उदाहरणों और उदाहरण विधियों का उपयोग करना है और सिंगलेट्स को लागू करना है और कार्यक्रम की शुरुआत में पसंद है।
Miško Hevery , जो 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();
मुख्य विचार अपनी कक्षाओं से निर्भरता को कम करना है। इस तरह से कोड बहुत अधिक एक्स्टेंसिबल है और, मेरे लिए सबसे महत्वपूर्ण हिस्सा, परीक्षण योग्य है। परीक्षण योग्य होना क्यों अधिक महत्वपूर्ण है? क्योंकि मैं हमेशा लाइब्रेरी कोड नहीं लिखता हूं, इसलिए एक्स्टेंसिबिलिटी इतनी महत्वपूर्ण नहीं है, लेकिन जब मैं रिफ्लेक्टिंग करता हूं तो टेस्टिबिलिटी महत्वपूर्ण है। वैसे भी, परीक्षण योग्य कोड आमतौर पर एक्स्टेंसिबल कोड प्राप्त करता है, इसलिए यह वास्तव में एक या तो स्थिति नहीं है।
मिचो हेवेरी एकल और सिंगलेट्स (एक पूंजी एस के साथ या बिना) के बीच एक स्पष्ट अंतर भी करता है। अंतर बहुत सरल है। एक कम मामले "एस" वाले सिंगलेट्स को सूचकांक / मुख्य में वायरिंग द्वारा लागू किया जाता है। आप उस वर्ग की किसी वस्तु को तुरंत भेज देते हैं जो सिंग्लटन पैटर्न को लागू नहीं करता है और इस बात का ध्यान रखता है कि आप केवल उस उदाहरण को किसी अन्य उदाहरण से पास करें जिसकी उसे आवश्यकता है। दूसरी ओर, एक राजधानी "एस" के साथ सिंगलटन शास्त्रीय (विरोधी) पैटर्न का कार्यान्वयन है। मूल रूप से भेस में एक वैश्विक जो PHP दुनिया में ज्यादा उपयोग नहीं है। मैंने इस बिंदु तक नहीं देखा है। यदि आप चाहते हैं कि आपके सभी वर्गों द्वारा उपयोग किया जाने वाला एकल DB कनेक्शन इस तरह से किया जाए तो बेहतर है:
$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);
}
}
एकमात्र स्थिति जहां मैं उपयोग करूंगा (और मैंने उन्हें PHP 5.3 में जावास्क्रिप्ट प्रोटोटाइप ऑब्जेक्ट की नकल करने के लिए उपयोग किया है) स्थिर सदस्य हैं जब मुझे पता है कि संबंधित फ़ील्ड में समान मान क्रॉस-इंस्टेंस होगा। उस बिंदु पर आप एक स्थिर संपत्ति और शायद स्थिर गेट्टर / सेटर विधियों की एक जोड़ी का उपयोग कर सकते हैं। वैसे भी, उदाहरण के सदस्य के साथ स्थैतिक सदस्य को ओवरराइड करने की संभावना जोड़ना न भूलें। उदाहरण के लिए, Zend फ्रेमवर्क एक स्थिर संपत्ति का उपयोग कर रहा था ताकि उदाहरणों में प्रयुक्त DB एडाप्टर वर्ग का नाम निर्दिष्ट किया जा सके Zend_Db_Table
। जब से मैंने इनका उपयोग किया है, तब से थोड़ी देर हो गई है, इसलिए यह अब प्रासंगिक नहीं हो सकता है, लेकिन यह है कि मुझे यह याद है।
स्थैतिक गुणों से निपटने के लिए स्थिर तरीके कार्य नहीं होने चाहिए। PHP में फ़ंक्शन होते हैं और हमें उनका उपयोग करना चाहिए।