2010-09-12 12 views
12

सी और जावा में कुछ काम करने के बाद मैं PHP में जंगली पश्चिम कानूनों से अधिक से अधिक नाराज रहा हूं। मुझे वास्तव में क्या लगता है कि PHP की कमी सख्त डेटा प्रकार है। तथ्य यह है कि स्ट्रिंग ('0') == (int) 0 == (बूलियन) झूठा एक उदाहरण है।PHP टाइपकास्टिंग - अच्छा या बुरा?

आप इस बात पर भरोसा नहीं कर सकते कि डेटा प्रकार फ़ंक्शन रिटर्न क्या है। आप किसी फ़ंक्शन के तर्कों को किसी विशिष्ट प्रकार के होने के लिए मजबूर नहीं कर सकते हैं, जो किसी गैर सख्त तुलना की वजह से अप्रत्याशित रूप से कुछ हो सकता है। सबकुछ का ख्याल रखा जा सकता है, लेकिन यह अभी भी अप्रत्याशित बग के लिए खुलता है।

क्या यह विधि के लिए प्राप्त टाइपकास्ट तर्कों के लिए अच्छा या बुरा अभ्यास है? और क्या वापसी का टाइप करना अच्छा है?

आईई

public function doo($foo, $bar) { 
    $foo = (int)$foo; 
    $bar = (float)$bar; 
    $result = $bar + $foo; 
    return (array)$result; 
} 

उदाहरण काफी बेवकूफ है और मैं इसे परीक्षण नहीं किया है, लेकिन मैं हर किसी के विचार हो जाता है लगता है। क्या PHP-God के लिए डेटा प्रकार को रूपांतरित करने का कोई कारण है, जैसा कि वह चाहता है, उन लोगों को देने के अलावा जो डेटा प्रकारों के बारे में नहीं जानते हैं PHP का उपयोग करते हैं?

+1

आपको लगता है कि कमजोर टाइपिंग (जैसे PHP, जावास्क्रिप्ट, स्मॉलटाक, सी, सी ++, आदि) एक दोष है, लेकिन यह PHP के डिजाइन का हिस्सा है, और इस प्रकार बदलने की संभावना नहीं है। यह उन विशेषताओं में से एक है जो PHP को सी-प्रकार की भाषा बनाता है। – GZipp

+2

@GZopp: सी और सी ++ कमजोर टाइप की गई भाषा नहीं हैं। –

+0

आपको वास्तव में एक निश्चित प्रकार के लिए तर्क की आवश्यकता हो सकती है, लेकिन यह केवल कक्षाओं और सरणी के साथ काम करता है, अन्य अंतर्निर्मित प्रकारों में नहीं। http://www.php.net/manual/en/functions.arguments.php#98425 – mwhite

उत्तर

20

बेहतर या बदतर के लिए, ढीले-टाइपिंग है "पीएचपी तरीका"। कई अंतर्निर्मित, और अधिकांश भाषा संरचनाएं, आप जो कुछ भी देते हैं, उस पर काम करेंगे - चुपचाप (और अक्सर खतरनाक रूप से) चीजों के पीछे उन्हें कास्टिंग (चीजों) को एक साथ फिट करने के लिए।

जावा/सी/सी ++ पृष्ठभूमि से स्वयं आ रहा है, PHP का ढीला-टाइपिंग मॉडल हमेशा मेरे लिए निराशा का स्रोत रहा है। लेकिन सालों से मुझे पता चला है कि, अगर मुझे PHP लिखना है तो मैं इसका बेहतर काम कर सकता हूं (यानी क्लीनर, सुरक्षित, अधिक टेस्टेबल कोड) PHP के "ढीलेपन" को गले लगाकर, इसे लड़ने के बजाय; और मैं इसके कारण एक खुश बंदर खत्म करता हूं।

कास्टिंग वास्तव में मेरी तकनीक के लिए मौलिक है - और (आईएमएचओ) यह एकमात्र तरीका है जो स्वच्छ, पठनीय PHP कोड का निर्माण करने का एकमात्र तरीका है जो एक अच्छी तरह से समझने योग्य, टेस्टेबल, निर्धारिक तरीके से मिश्रित प्रकार के तर्कों को संभालता है।

मुख्य बिंदु (जिसे आप स्पष्ट रूप से समझते हैं) यह है कि, PHP में, आप बस यह नहीं मान सकते कि एक तर्क वह प्रकार है जिसे आप उम्मीद करते हैं। ऐसा करने से, गंभीर परिणाम हो सकते हैं कि आपके ऐप उत्पादन के बाद तक पकड़ने की संभावना नहीं है।

<?php 

function displayRoomCount($numBoys, $numGirls) { 
    // we'll assume both args are int 

    // check boundary conditions 
    if(($numBoys < 0) || ($numGirls < 0)) throw new Exception('argument out of range'); 

    // perform the specified logic 
    $total = $numBoys + $numGirls; 
    print("{$total} people: {$numBoys} boys, and {$numGirls} girls \n"); 
} 

displayRoomCount(0, 0); // (ok) prints: "0 people: 0 boys, and 0 girls" 

displayRoomCount(-10, 20); // (ok) throws an exception 

displayRoomCount("asdf", 10); // (wrong!) prints: "10 people: asdf boys, and 10 girls" 

एक को सुलझाने इस, प्रकार है कि समारोह स्वीकार कर सकते हैं सीमित करने के लिए एक अपवाद फेंक अमान्य प्रकार का पता लगाया जाता है जब है के लिए दृष्टिकोण:

इस बिंदु को वर्णन करने के लिए। दूसरों ने पहले से ही इस दृष्टिकोण का उल्लेख किया है। यह मेरे जावा/सी/सी ++ सौंदर्यशास्त्र के लिए अच्छी तरह से अपील करता है, और मैंने वर्षों और वर्षों के लिए PHP में इस दृष्टिकोण का पालन किया। संक्षेप में, इसमें कुछ भी गलत नहीं है, लेकिन यह "द PHP वे" के खिलाफ जाता है, और थोड़ी देर के बाद, यह तैराकी अप-स्ट्रीम की तरह महसूस करना शुरू कर देता है।

वैकल्पिक रूप से, कास्टिंग यह सुनिश्चित करने के लिए एक सरल और साफ तरीका प्रदान करता है कि कार्य प्रत्येक संभावित प्रकार के लिए विशिष्ट तर्क लिखने के बिना, सभी संभावित इनपुट के लिए निर्धारित रूप से व्यवहार करता है।

कास्टिंग का उपयोग करना, हमारे उदाहरण अब हो जाता है:

<?php 

function displayRoomCount($numBoys, $numGirls) { 
    // we cast to ensure that we have the types we expect 
    $numBoys = (int)$numBoys; 
    $numGirls = (int)$numGirls; 

    // check boundary conditions 
    if(($numBoys < 0) || ($numGirls < 0)) throw new Exception('argument out of range'); 

    // perform the specified logic 
    $total = $numBoys + $numGirls; 
    print("{$total} people: {$numBoys} boys, and {$numGirls} girls \n"); 
} 

displayRoomCount("asdf", 10); // (ok now!) prints: "10 people: 0 boys, and 10 girls" 

समारोह अब अपेक्षा के अनुरूप व्यवहार करता है। वास्तव में, यह दिखाना आसान है कि फ़ंक्शन का व्यवहार अब सभी संभावित इनपुट के लिए अच्छी तरह से परिभाषित किया गया है। ऐसा इसलिए है क्योंकि कास्ट ऑपरेशन सभी संभावित इनपुट के लिए अच्छी तरह परिभाषित है; कास्ट सुनिश्चित करते हैं कि हम हमेशा पूर्णांक के साथ काम कर रहे हैं; और बाकी का कार्य लिखा गया है ताकि सभी संभावित पूर्णांक के लिए अच्छी तरह से परिभाषित किया जा सके।

Rules for type-casting in PHP are documented here, (पृष्ठ के नीचे प्रकार-विशिष्ट लिंक मध्य-मार्ग देखें - उदाहरण: "पूर्णांक में कनवर्ट करना")।

इस दृष्टिकोण में अतिरिक्त लाभ है कि फ़ंक्शन अब इस तरह से व्यवहार करेगा जो अन्य PHP अंतर्निहित, और भाषा संरचनाओं के अनुरूप है। उदाहरण के लिए:

// assume $db_row read from a database of some sort 
displayRoomCount($db_row['boys'], $db_row['girls']); 

ठीक काम करेंगे, तथ्य यह है कि $db_row['boys'] और $db_row['girls'] वास्तव में कर रहे तार कि संख्यात्मक मान हैं के बावजूद। यह इस तरह से संगत है कि औसत PHP डेवलपर (जो सी, सी ++, या जावा नहीं जानता) इसे काम करने की उम्मीद करेगा।


वापसी मान कास्टिंग के लिए के रूप में: ऐसा करने से, जब तक आप जानते हैं कि आप एक संभावित मिश्रित प्रकार चर है, और आप हमेशा यह सुनिश्चित करें कि वापसी मान एक विशिष्ट प्रकार है चाहता हूँ में बहुत कम मतलब नहीं है। यह उस बिंदु के बजाय कोड में मध्यवर्ती बिंदुओं पर अक्सर होता है जहां आप किसी फ़ंक्शन से वापस आ रहे हैं।

एक व्यावहारिक उदाहरण:

<?php 

function getParam($name, $idx=0) { 
    $name = (string)$name; 
    $idx = (int)$idx; 

    if($name==='') return null; 
    if($idx<0) $idx=0; 

    // $_REQUEST[$name] could be null, or string, or array 
    // this depends on the web request that came in. Our use of 
    // the array cast here, lets us write generic logic to deal with them all 
    // 
    $param = (array)$_REQUEST[$name]; 

    if(count($param) <= $idx) return null; 
    return $param[$idx]; 
} 

// here, the cast is used to ensure that we always get a string 
// even if "fullName" was missing from the request, the cast will convert 
// the returned NULL value into an empty string. 
$full_name = (string)getParam("fullName"); 

आप अंदाजा हो।


पकड़ लिया है के एक जोड़े

  • पीएचपी की कास्टिंग के तंत्र के बारे में पता होना करने के लिए कर रहे हैं बहुत चालाक "नहीं-op" कलाकारों का अनुकूलन करने नहीं है। इसलिए कास्टिंग हमेशा चर की एक प्रति बनने का कारण बनता है। ज्यादातर मामलों में, यह कोई समस्या नहीं है, लेकिन यदि आप नियमित रूप से इस दृष्टिकोण का उपयोग करते हैं, तो आपको इसे अपने दिमाग के पीछे रखना चाहिए। इस वजह से, कास्टिंग संदर्भ और बड़े सरणी के साथ अप्रत्याशित मुद्दों का कारण बन सकता है। अधिक जानकारी के लिए PHP Bug Report #50894 देखें।

  • PHP में, एक पूर्ण संख्या जो पूर्णांक (या बहुत छोटा) एक पूर्णांक प्रकार के रूप में प्रतिनिधित्व करने के लिए है, स्वचालित रूप से एक फ्लोट (या एक डबल, यदि आवश्यक हो) के रूप में प्रदर्शित किया जाएगा। इसका मतलब है कि का परिणाम वास्तव में एक फ्लोट हो सकता है, और यदि आप इसे int में डाल देते हैं तो परिणामस्वरूप संख्या गड़बड़ी होगी। इसलिए, यदि आप ऐसे कार्यों का निर्माण कर रहे हैं जिन्हें बड़ी संख्या में काम करने की आवश्यकता है, तो आपको इसे ध्यान में रखना चाहिए, और शायद कुछ अन्य दृष्टिकोण पर विचार करना चाहिए।


लंबे पद के लिए खेद है, लेकिन यह एक विषय है कि मैं गहराई में माना जाता है, और वर्षों के माध्यम से, मैं काफी ज्ञान (और राय) का एक सा द्वारा एकत्रित किए गए इसके बारे में। इसे यहां डालकर, मुझे आशा है कि किसी को यह उपयोगी लगेगा।

+1

यह वास्तव में सहायक पाया - यदि संभव हो तो कई बार उभरा होगा। – cantera

0

नहीं, टाइपकास्ट करना अच्छा नहीं है क्योंकि आप नहीं जानते कि अंत में आपके पास क्या होगा। मैं व्यक्तिगत रूप से intval(), floatval(), आदि

+1

कैसा है? या तो कलाकार सफल होगा और आपके पास सही प्रकार का मूल्य होगा, या निष्पादन विफल हो जाएगा (PHP संस्करण के आधार पर एक अपवाद फेंक दिया जाएगा या PHP बम जाएगा)। क्या मैं यहाँ कुछ याद कर रहा हूँ? –

+0

मैं बिली के बारे में भी उत्सुक हूं। अंतराल() seams (int) – Anders

2

जटिल कार्यों के लिए type hinting का उपयोग कर सुझावों का उपयोग करने का सुझाव दूंगा। यदि आपको मूल्य + प्रकार की तुलना करने की आवश्यकता है तो आप तुलना के लिए "===" का उपयोग कर सकते हैं।

(0 === false) => results in false 
(0 == false) => results in true 

इसके अलावा आप return (array)$result; लिखते हैं जो कोई समझ नहीं आता है। यदि आप रिटर्न टाइप को सरणी बनाना चाहते हैं तो इस मामले में आप क्या चाहते हैं return array($result) है।

+0

के साथ टाइप कास्टिंग के समान ही करने के लिए मैं उदाहरण में त्रुटियों से अवगत हूं। जिस तरह से मैं इसे सी में करूँगा, लेकिन जैसा कि आप कहते हैं कि मैं निश्चित रूप से PHP में ऐसा नहीं करूँगा। यह ज्यादातर उदाहरण में स्थिरता के लिए था। मुझे टाइपिंग संकेत के बारे में पता है, लेकिन यह आदिम प्रकारों के लिए काम नहीं करता है :(यह सिर्फ – Anders

2

मुझे नहीं लगता कि यह बुरा है, लेकिन मैं एक कदम आगे जाऊंगा: जटिल प्रकारों के लिए type hinting का उपयोग करें, और यदि आप एक साधारण प्रकार की अपेक्षा नहीं करते हैं तो अपवाद फेंक दें। इस तरह आप ग्राहकों को कलाकारों के साथ किसी भी लागत/समस्याओं के बारे में अवगत कराते हैं (जैसे कि int -> float या float -> int से परिशुद्धता का नुकसान)।

उपरोक्त कोड में सरणी के लिए आपकी कास्ट भ्रामक है - आपको केवल एक मान वाला एक नया सरणी बनाना चाहिए।

सभी ने कहा कि, अपने उदाहरण से ऊपर हो जाता है:

public function doo($foo, $bar) { 
    if (!is_int($foo)) throw new InvalidArgumentException(); 
    if (!is_float($bar)) throw new InvalidArgumentException(); 
    $result = $bar + $foo; 
    return array($result); 
} 
+0

वर्ग के लिए "int" वर्ग की तलाश करेगा, मुझे लगता है कि यह मेरे विचारों में एक बड़ा सुधार है। क्या कोई ओवरहेड चिंतित है? – Anders

+2

हाँ, PHP में एक फ़ंक्शन को कॉल करना धीमा है। लेकिन समयपूर्व अनुकूलन सभी बुराइयों की जड़ इन मामूली, महत्वहीन मंदी के बारे में नहीं सोचता है, लेकिन आपके कोड की पठनीयता और रखरखाव के बारे में सोचें;) – NikiC

+0

@Anders: हाँ, वहां ओवरहेड है, लेकिन मुझे यह महत्वपूर्ण नहीं लगता है। PHP को किसी भी मामले में कास्ट करने के क्रम में प्रकार की जांच करनी है। बेशक, चेक मुफ्त में नहीं है। –

4

पीएचपी के अगले संस्करण (शायद 5.4) will support scalar type hinting in arguments

लेकिन इसके अलावा: गतिशील प्रकार रूपांतरण वास्तव में ऐसा कुछ नहीं है जिसे आपको नफरत और टालना चाहिए। अधिकतर यह उम्मीद के रूप में काम करेगा। और अगर ऐसा नहीं होता है, तो यह किसी प्रकार की is_* की जाँच करके,, ठीक सख्त तुलना का उपयोग करके ... ...

+2

पर महत्वपूर्ण बाधाएं मिलती हैं, मुझे यकीन नहीं है कि यह सहमति हुई थी (फिर फिर, php पर।आंतरिक में केवल 2 लोगों को रिहाई की व्यवस्था करने के लिए निजी तौर पर बात करना पड़ता है)। हालांकि इसके लिए एक पैच है, मुझे यकीन नहीं है कि यह सहमति हुई है कि यह PHP में होगा। – Ross

+0

एरर .. php पहले से ही संकेत संकेत (और थोड़ी देर के लिए है) का समर्थन करता है। –

+0

@ बिली: यह स्केलर प्रकार संकेतों का समर्थन नहीं करता था और यही वह है जिसके बारे में हम यहां बात कर रहे हैं। – NikiC

संबंधित मुद्दे