วิธีหลีกเลี่ยง isset () และว่าง ()


98

ฉันมีแอปพลิเคชันรุ่นเก่าหลายตัวที่ส่งข้อความ "xyz is undefined" และ "undefined offset" จำนวนมากเมื่อทำงานในระดับข้อผิดพลาด E_NOTICE เนื่องจากการมีอยู่ของตัวแปรไม่ได้รับการตรวจสอบอย่างชัดเจนโดยใช้isset()และรวบรวม

ฉันกำลังพิจารณาดำเนินการผ่านสิ่งเหล่านี้เพื่อให้เข้ากันได้กับ E_NOTICE เนื่องจากการแจ้งเตือนเกี่ยวกับตัวแปรที่ขาดหายไปหรือการชดเชยอาจเป็นตัวช่วยชีวิตได้อาจมีการปรับปรุงประสิทธิภาพเล็กน้อยที่จะได้รับและโดยรวมแล้วเป็นวิธีที่สะอาดกว่า

แต่ผมไม่ชอบสิ่งที่ก่อให้เกิดหลายร้อยisset() empty()และarray_key_exists()s ไม่ให้รหัสของฉัน มันป่องอ่านได้น้อยลงโดยไม่ได้รับคุณค่าหรือความหมายอะไรเลย

ฉันจะจัดโครงสร้างโค้ดของฉันโดยไม่มีการตรวจสอบตัวแปรมากเกินไปได้อย่างไรในขณะเดียวกันก็เข้ากันได้กับ E_NOTICE


6
ฉันเห็นด้วยอย่างสมบูรณ์ นั่นเป็นเหตุผลที่ฉันชอบ Zend Framework มากโมดูลคำขอนั้นดีมากที่นั่น หากฉันกำลังทำงานกับแอพขนาดเล็กฉันมักจะเขียนโค้ดคลาสคำของ่ายๆด้วยเมธอดมายากล __set และ __get ที่ทำงานคล้ายกับคำขอของ ZF ด้วยวิธีนี้ฉันจะหลีกเลี่ยงการเกิด isset และว่างเปล่าในโค้ดของฉัน วิธีนี้สิ่งที่คุณต้องใช้คือ if (count ($ arr)> 0) บนอาร์เรย์ก่อนที่จะวนซ้ำและ if (null! == $ variable) ที่จุดวิกฤตไม่กี่แห่ง มันดูสะอาดขึ้นมาก
Richard Knop

คำตอบ:


128

สำหรับผู้ที่สนใจฉันได้ขยายหัวข้อนี้เป็นบทความเล็ก ๆ ซึ่งให้ข้อมูลด้านล่างในรูปแบบที่ค่อนข้างดีกว่า: คำแนะนำขั้นสุดท้ายสำหรับการตั้งค่าและว่างเปล่าของ PHP


IMHO คุณควรคิดว่าไม่ใช่แค่การสร้างแอป "E_NOTICE เข้ากันได้" แต่เป็นการปรับโครงสร้างทั้งหมด มีหลายร้อยคะแนนในโค้ดของคุณที่พยายามใช้ตัวแปรที่ไม่มีอยู่จริงเป็นประจำดูเหมือนเป็นโปรแกรมที่มีโครงสร้างไม่ดี การพยายามเข้าถึงตัวแปรที่ไม่มีอยู่จริงไม่ควรเกิดขึ้นภาษาอื่นหยุดชะงักในเวลาคอมไพล์ การที่ PHP อนุญาตให้คุณทำมันไม่ได้หมายความว่าคุณควร

คำเตือนเหล่านี้มีไว้เพื่อช่วยคุณไม่ให้คุณรำคาญ หากคุณได้รับคำเตือน"คุณกำลังพยายามทำงานกับสิ่งที่ไม่มีอยู่จริง!" ปฏิกิริยาของคุณควรเป็น"อ๊ะฉันไม่ดีให้ฉันแก้ไขโดยเร็วที่สุด" คุณจะบอกความแตกต่างระหว่าง"ตัวแปรที่ทำงานได้ดีโดยไม่ได้กำหนด"กับรหัสที่ไม่ถูกต้องตรงไปตรงมาซึ่งอาจนำไปสู่ข้อผิดพลาดร้ายแรงได้อย่างไร นี่คือเหตุผลว่าทำไมคุณถึงออกเสมอ การปิดการรายงานข้อผิดพลาดมีไว้สำหรับสภาพแวดล้อมการใช้งานจริงเท่านั้นเพื่อหลีกเลี่ยงการรั่วไหลของข้อมูลและมอบประสบการณ์การใช้งานที่ดียิ่งขึ้นให้กับผู้ใช้แม้จะเผชิญกับรหัสบั๊กเสมอพัฒนากับรายงานข้อผิดพลาดหันไป 11และให้เสียบไปที่รหัสของคุณจนกว่าจะไม่ได้เป็นคนเดียวNOTICE


ทำอย่างละเอียด:

คุณมักจะต้องการissetหรือemptyอยู่ที่ไหนสักแห่งในโค้ดของคุณวิธีเดียวที่จะลดการเกิดขึ้นคือการเริ่มต้นตัวแปรของคุณอย่างเหมาะสม ขึ้นอยู่กับสถานการณ์มีหลายวิธีในการทำเช่นนั้น:

อาร์กิวเมนต์ของฟังก์ชัน:

function foo ($bar, $baz = null) { ... }

ไม่จำเป็นต้องมีการตรวจสอบว่าเป็น$barหรือ$bazมีการตั้งค่าฟังก์ชั่นภายในเพราะคุณเพียงแค่ตั้งพวกเขาทั้งหมดที่คุณต้องกังวลเกี่ยวกับคือถ้าประเมินค่าของพวกเขาไปtrueหรือfalse(หรือสิ่งอื่น)

ตัวแปรปกติทุกที่:

$foo = null;
$bar = $baz = 'default value';

เริ่มต้นตัวแปรของคุณที่ด้านบนสุดของบล็อกโค้ดที่คุณจะใช้ สิ่งนี้จะช่วยแก้ปัญหา!issetปัญหาทำให้แน่ใจว่าตัวแปรของคุณมีค่าดีฟอลต์ที่ทราบอยู่เสมอช่วยให้ผู้อ่านทราบว่าโค้ดต่อไปนี้จะทำงานอย่างไรและยังทำหน้าที่เป็นเอกสารประกอบในตัวเองอีกด้วย

อาร์เรย์:

$defaults = array('foo' => false, 'bar' => true, 'baz' => 'default value');
$values = array_merge($defaults, $incoming_array);

เช่นเดียวกับข้างต้นคุณกำลังเริ่มต้นอาร์เรย์ด้วยค่าเริ่มต้นและเขียนทับด้วยค่าจริง

ในกรณีที่เหลือสมมติว่าแม่แบบที่คุณส่งออกค่าที่ตัวควบคุมอาจกำหนดหรือไม่ก็ได้คุณจะต้องตรวจสอบ:

<table>
    <?php if (!empty($foo) && is_array($foo)) : ?>
        <?php foreach ($foo as $bar) : ?>
            <tr>...</tr>
        <?php endforeach; ?>
    <?php else : ?>
        <tr><td>No Foo!</td></tr>
    <?php endif; ?>
</table>

หากคุณพบว่าตัวเองใช้งานเป็นประจำarray_key_existsคุณควรประเมินว่าคุณใช้มันเพื่ออะไร ครั้งเดียวที่สร้างความแตกต่างอยู่ที่นี่:

$array = array('key' => null);
isset($array['key']); // false
array_key_exists('key', $array); // true

ตามที่ระบุไว้ข้างต้นแม้ว่าคุณจะเริ่มต้นตัวแปรของคุณอย่างถูกต้องคุณไม่จำเป็นต้องตรวจสอบว่ามีคีย์อยู่หรือไม่เพราะคุณรู้ดี หากคุณได้รับอาร์เรย์จากแหล่งภายนอกค่าส่วนใหญ่จะไม่เป็นnullแต่'', 0, '0', falseหรือสิ่งที่ชอบคือค่าคุณสามารถประเมินด้วยissetหรือemptyขึ้นอยู่กับเจตนาของคุณ หากคุณตั้งค่าคีย์อาร์เรย์เป็นประจำnullและต้องการให้มันมีความหมายอะไร แต่falseเช่นถ้าในตัวอย่างข้างต้นผลลัพธ์ที่แตกต่างกันissetและarray_key_existsสร้างความแตกต่างให้กับตรรกะโปรแกรมของคุณคุณควรถามตัวเองว่าทำไม การมีอยู่ของตัวแปรไม่ควรมีความสำคัญเพียง แต่ค่าของมันเท่านั้นที่ควรเป็นผล หากคีย์เป็นtrue/ falseแฟล็กให้ใช้trueหรือไม่false nullข้อยกเว้นเพียงอย่างเดียวสำหรับสิ่งนี้คือไลบรารีของบุคคลที่สามที่ต้องการnullหมายถึงบางสิ่ง แต่เนื่องจากnullการตรวจพบใน PHP นั้นยากมากฉันจึงยังไม่พบไลบรารีใด ๆ ที่ทำเช่นนี้


4
จริง แต่ความพยายามในการเข้าถึงที่ล้มเหลวส่วนใหญ่เป็นไปตามแนวif ($array["xyz"])แทนที่จะเป็นisset()หรือarray_key_exists()ที่ฉันพบว่าค่อนข้างถูกต้องตามกฎหมายไม่ใช่ปัญหาเชิงโครงสร้าง (แก้ไขฉันถ้าฉันเข้าใจผิด) การเพิ่มarray_key_exists()ก็ดูเหมือนเป็นการเสียประโยชน์สำหรับฉัน
Pekka

9
ฉันไม่สามารถนึกถึงกรณีใด ๆ ที่ฉันจะใช้array_key_existsแทนแบบธรรมดาisset($array['key'])หรือ!empty($array['key']). แน่นอนว่าทั้งคู่เพิ่มอักขระ 7 หรือ 8 ตัวในรหัสของคุณ แต่ฉันแทบจะไม่เรียกว่าปัญหา นอกจากนี้ยังช่วยชี้แจงรหัสของคุณ: if (isset($array['key']))หมายความว่าตัวแปรนี้เป็นทางเลือกและอาจไม่มีอยู่ในขณะที่if ($array['key'])หมายถึง "ถ้าเป็นจริง" หากคุณได้รับการแจ้งให้ทราบในครั้งหลังคุณก็รู้ว่าตรรกะของคุณผิดพลาดที่ไหนสักแห่ง
หลอกลวง

6
ฉันเชื่อว่าความแตกต่างระหว่าง isset () และ array_key_exists () คือค่าหลังจะคืนค่าเป็นจริงถ้าค่าเป็นโมฆะ isset () จะไม่
Htbaa

1
จริง แต่ฉันไม่สามารถนึกถึงกรณีการใช้งานที่มีเหตุผลที่ฉันต้องแยกความแตกต่างระหว่างตัวแปรที่ไม่มีอยู่จริงกับคีย์ชุดที่ค่าที่เป็นโมฆะ หากค่าประเมินเป็นเท็จความแตกต่างควรไม่มีความแตกต่าง :)
หลอกลวง

1
คีย์อาร์เรย์น่ารำคาญกว่าตัวแปรที่ไม่ได้กำหนด แต่ถ้าคุณไม่แน่ใจว่าอาร์เรย์ที่มีคีย์หรือไม่ก็หมายความว่าอย่างใดอย่างหนึ่งที่คุณไม่ได้กำหนดอาร์เรย์ตัวเองหรือคุณกำลังดึงมันออกมาจากแหล่งที่มาที่คุณทำไม่ได้ควบคุม ทั้งสองสถานการณ์ไม่ควรเกิดขึ้นบ่อยนัก และหากเกิดขึ้นคุณมีเหตุผลทุกประการที่จะตรวจสอบว่าอาร์เรย์มีสิ่งที่คุณคิดหรือไม่ เป็นมาตรการรักษาความปลอดภัย IMO
kijin

37

เพียงแค่เขียนฟังก์ชันสำหรับสิ่งนั้น สิ่งที่ต้องการ:

function get_string($array, $index, $default = null) {
    if (isset($array[$index]) && strlen($value = trim($array[$index])) > 0) {
        return get_magic_quotes_gpc() ? stripslashes($value) : $value;
    } else {
        return $default;
    }
}

ซึ่งคุณสามารถใช้เป็น

$username = get_string($_POST, 'username');

ทำเช่นเดียวกันสำหรับสิ่งเล็ก ๆ น้อย ๆ เช่นget_number(), get_boolean(), get_array()และอื่น ๆ


5
สิ่งนี้ดูดีและตรวจสอบ magic_quotes ด้วย ดี!
Pekka

ฟังก์ชั่นเยี่ยม! ขอบคุณมากสำหรับการแบ่งปัน
Mike Moore

3
ขอให้สังเกตว่า $ _POST [ 'บางสิ่งบางอย่าง'] <input name="something[]" />อาจจะกลับอาร์เรย์เช่นปัจจัยการผลิตด้วย สิ่งนี้จะทำให้เกิดข้อผิดพลาด (เนื่องจากไม่สามารถใช้การตัดแต่งกับอาร์เรย์ได้) โดยใช้โค้ดด้านบนในกรณีนี้ควรใช้is_stringและอาจเป็นไปstrvalได้ นี่ไม่ใช่แค่กรณีที่ควรใช้get_arrayอย่างใดอย่างหนึ่งเนื่องจากอินพุตของผู้ใช้ (เป็นอันตราย) อาจเป็นอะไรก็ได้และตัวแยกวิเคราะห์อินพุตของผู้ใช้ก็ไม่ควรเกิดข้อผิดพลาดอยู่ดี
Ciantic

1
ฉันใช้ฟังก์ชันประเภทเดียวกัน แต่กำหนดไว้เช่นนี้: function get_value (& $ item, $ default = NULL) {return isset ($ item)? $ item: $ default; } ข้อดีของฟังก์ชันนี้คือคุณสามารถเรียกใช้ด้วยอาร์เรย์ตัวแปรและวัตถุ ข้อเสียเปรียบคือ $ item จะเริ่มต้น (เป็น null) หลังจากนั้นหากไม่ได้
จ้า

คุณควรปิดคำพูดวิเศษทั่วโลกแทนที่จะจัดการกับคำพูดเหล่านี้ใน 1 ฟังก์ชัน มีแหล่งข้อมูลมากมายบนอินเทอร์เน็ตที่อธิบายคำพูดเกี่ยวกับเวทมนตร์
Kayla

13

ฉันเชื่อว่าหนึ่งในวิธีที่ดีที่สุดในการจัดการกับปัญหานี้คือการเข้าถึงค่าของอาร์เรย์ GET และ POST (COOKIE, SESSION ฯลฯ ) ผ่านชั้นเรียน

สร้างคลาสสำหรับแต่ละอาร์เรย์เหล่านั้นและประกาศ__getและ__setวิธีการ ( โอเวอร์โหลด ) __getยอมรับหนึ่งอาร์กิวเมนต์ซึ่งจะเป็นชื่อของค่า วิธีนี้ควรตรวจสอบค่านี้ในอาร์เรย์ส่วนกลางที่เกี่ยวข้องโดยใช้isset()หรือempty()และส่งคืนค่าหากมีอยู่หรือnull(หรือค่าเริ่มต้นอื่น ๆ ) เป็นอย่างอื่น

หลังจากที่คุณสามารถเข้าถึงค่าอาร์เรย์มั่นใจในลักษณะนี้$POST->usernameและทำในการตรวจสอบใด ๆ หากมีความจำเป็นใด ๆ โดยไม่ต้องใช้isset()หรือempty()s หากusernameไม่มีอยู่ในอาร์เรย์ส่วนกลางที่เกี่ยวข้องnullจะถูกส่งกลับดังนั้นจะไม่มีการสร้างคำเตือนหรือประกาศ


1
นี่เป็นความคิดที่ดีและเป็นสิ่งที่ฉันพร้อมที่จะปรับโครงสร้างรหัสใหม่ +1
Pekka

น่าเสียดายที่คุณไม่สามารถทำให้อินสแตนซ์เหล่านั้นเป็น superglobal ได้เว้นแต่คุณจะกำหนดให้เป็น $ _GET หรือ $ _POST ซึ่งจะค่อนข้างน่าเกลียด แต่คุณสามารถใช้คลาสคงที่ได้แน่นอน ...
ThiefMaster

1
คุณไม่สามารถใช้ getters และ setters ใน "static class" ได้ และการเขียนหนึ่งคลาสต่อตัวแปรนั้นเป็นการปฏิบัติที่ไม่ดีเนื่องจากมีความหมายถึงการทำสำเนาโค้ดซึ่งไม่ดี ฉันไม่คิดว่าวิธีนี้จะเพียงพอที่สุด
จ้า

สมาชิกแบบคงที่สาธารณะของคลาสจะทำหน้าที่เหมือน superglobal นั่นคือ: HTTP :: $ POST-> ชื่อผู้ใช้ที่คุณสร้างอินสแตนซ์ HTTP :: $ POST ณ จุดหนึ่งก่อนการใช้งานเช่น คลาส HTTP {สาธารณะคง $ POST = array (); ... }; HTTP :: $ POST = someClass ใหม่ ($ _ POST); ...
velcrow

6

ฉันไม่รังเกียจที่จะใช้array_key_exists()ฟังก์ชันนี้ อันที่จริงฉันชอบใช้ฟังก์ชันเฉพาะนี้มากกว่าที่จะใช้ฟังก์ชันแฮ็กซึ่งอาจเปลี่ยนพฤติกรรมของพวกเขาในอนาคตเช่นemptyและisset (ขีดฆ่าเพื่อหลีกเลี่ยงความอ่อนไหว )


อย่างไรก็ตามฉันใช้ฟังก์ชันง่ายๆที่มีประโยชน์ในเรื่องนี้และสถานการณ์อื่น ๆในการจัดการกับดัชนีอาร์เรย์ :

function Value($array, $key, $default = false)
{
    if (is_array($array) === true)
    {
        settype($key, 'array');

        foreach ($key as $value)
        {
            if (array_key_exists($value, $array) === false)
            {
                return $default;
            }

            $array = $array[$value];
        }

        return $array;
    }

    return $default;
}

สมมติว่าคุณมีอาร์เรย์ต่อไปนี้:

$arr1 = array
(
    'xyz' => 'value'
);

$arr2 = array
(
    'x' => array
    (
        'y' => array
        (
            'z' => 'value',
        ),
    ),
);

คุณจะเอา "ค่า" ออกจากอาร์เรย์ได้อย่างไร? ง่าย:

Value($arr1, 'xyz', 'returns this if the index does not exist');
Value($arr2, array('x', 'y', 'z'), 'returns this if the index does not exist');

เรามียูนิและอาร์เรย์หลายมิติครอบคลุมอยู่แล้วเราจะทำอะไรได้อีก?


ยกตัวอย่างรหัสต่อไปนี้:

$url = '/programming/1960509';
$domain = parse_url($url);

if (is_array($domain) === true)
{
    if (array_key_exists('host', $domain) === true)
    {
        $domain = $domain['host'];
    }

    else
    {
        $domain = 'N/A';
    }
}
else
{
    $domain = 'N/A';
}

ค่อนข้างน่าเบื่อใช่ไหม นี่คืออีกวิธีหนึ่งที่ใช้Value()ฟังก์ชัน:

$url = '/programming/1960509';
$domain = Value(parse_url($url), 'host', 'N/A');

ตัวอย่างเพิ่มเติมลองใช้RealIP()ฟังก์ชันเพื่อทดสอบ:

$ip = Value($_SERVER, 'HTTP_CLIENT_IP', Value($_SERVER, 'HTTP_X_FORWARDED_FOR', Value($_SERVER, 'REMOTE_ADDR')));

เรียบร้อยเหรอ? ;)


6
"อาศัยฟังก์ชั่นการแฮ็กที่อาจเปลี่ยนพฤติกรรมได้ในอนาคต"?! ขอโทษนะ แต่นั่นเป็นเรื่องที่ไร้สาระที่สุดที่ฉันได้ยินมาตลอดสัปดาห์ ประการแรกissetและemptyเป็นโครงสร้างภาษาไม่ใช่ฟังก์ชัน ประการที่สองหากฟังก์ชัน / ภาษาของไลบรารีหลักใด ๆเปลี่ยนแปลงพฤติกรรมของพวกเขาคุณอาจเมาหรือไม่ก็ได้ ถ้าarray_key_existsเปลี่ยนพฤติกรรมล่ะ? คำตอบคือใช้ไม่ได้ตราบเท่าที่คุณใช้เป็นเอกสาร และissetมีการจัดทำเอกสารให้ใช้อย่างแน่นอน ฟังก์ชันกรณีที่เลวร้ายที่สุดจะเลิกใช้งานในเวอร์ชันหลักหรือสองเวอร์ชัน NIH syndrome แย่แล้ว!
หลอกลวง

ฉันขอโทษที่หลอกลวง แต่ก่อนอื่นแฮ็คจะเป็นตัวเอียงในกรณีที่คุณไม่สังเกตเห็น =) ประการที่สองคุณหมายความว่าไม่ควรพึ่งพาarray_key_exists()การตรวจสอบว่ามีคีย์อยู่ในอาร์เรย์หรือไม่! array_key_exists()ถูกสร้างขึ้นมาเพื่อสิ่งนั้นฉันค่อนข้างจะพึ่งพามันเพื่อจุดประสงค์นี้มากกว่าisset()และโดยเฉพาะempty()ซึ่งมีคำอธิบายอย่างเป็นทางการ: "กำหนดว่าตัวแปรว่างเปล่า" ไม่ได้กล่าวถึงอะไรเลยหากมีอยู่จริง แสดงความคิดเห็นและลงคะแนนโหวตของคุณเป็นหนึ่งในผู้ที่ไร้สาระที่สุดที่ผมเคยร่วมเป็นสักขีพยานทุกเดือน
Alix Axel

3
ฉันกำลังพูดissetและemptyไม่น่าเชื่อถือมากหรือน้อยไปกว่าarray_key_existsและสามารถทำงานเดียวกันได้ ตัวอย่างที่สองที่ยืดยาวของคุณสามารถเขียนได้เช่นเดียว$domain = isset($domain['host']) ? $domain['host'] : 'N/A';กับคุณสมบัติภาษาหลักเท่านั้นไม่จำเป็นต้องเรียกใช้ฟังก์ชันพิเศษหรือการประกาศใด ๆ (โปรดทราบว่าฉันไม่จำเป็นต้องสนับสนุนการใช้ตัวดำเนินการ ternary แม้ว่า; o)) สำหรับตัวแปรสเกลาร์ธรรมดาคุณจะยังคงต้องใช้issetหรือemptyและคุณสามารถใช้ตัวแปรเหล่านี้สำหรับอาร์เรย์ได้ในลักษณะเดียวกัน "ความน่าเชื่อถือ" เป็นเหตุผลที่ไม่ดีสำหรับการไม่ทำเช่นนั้น
หลอกลวง

1
คุณชี้ประเด็นของคุณแม้ว่าฉันจะไม่เห็นด้วยกับสิ่งที่คุณพูดส่วนใหญ่ ฉันคิดว่าคุณเข้าใจผิดในกรณีมากกว่า 90% เช่นฉันใช้ค่า "0" ในช่องที่ซ่อนอยู่ในแบบฟอร์มตลอดเวลา ฉันยังเชื่อว่าวิธีแก้ปัญหาที่ฉันให้มาไม่สมควรได้รับการโหวตลดลงและอาจมีประโยชน์กับ Pekka บ้าง
Alix Axel

2
ในขณะที่ @deceze มีจุดที่มีฟังก์ชั่นที่กำหนดเอง - ฉันมักจะใช้จุดยืนเดียวกัน - วิธีการค่า () ดูน่าสนใจพอที่ฉันจะดู ฉันคิดว่าคำตอบและผลที่ตามมาจะช่วยให้ทุกคนที่สะดุดกับมันในภายหลังสามารถตัดสินใจได้เอง +1.
Pekka

3

ฉันอยู่ตรงนี้กับคุณ. แต่นักออกแบบ PHP ได้ทำผิดพลาดที่เลวร้ายยิ่งกว่านั้น ไม่มีการกำหนดฟังก์ชันที่กำหนดเองสำหรับการอ่านค่าใด ๆ ไม่มีวิธีใด ๆ เลย


1
isset () สิ่งของ การทำให้ทุกอย่างเป็นโมฆะโดยค่าเริ่มต้นจะช่วยประหยัดปัญหาได้มาก
vava

2
และนี่คือ 'ทุกสิ่งทุกอย่าง' คืออะไร? ดูเหมือนว่าจะเป็นการสิ้นเปลืองสำหรับ PHP ที่จะต้องจินตนาการถึงชื่อตัวแปรที่เป็นไปได้ทุกตัวและตั้งค่าแต่ละตัวแปรเป็น NULL เพื่อให้นักพัฒนาที่ขี้เกียจสามารถหลีกเลี่ยงการพิมพ์ 5 อักขระได้
Lotus Notes

5
@ ไบรอนดูสิมันง่ายมากภาษาอื่น ๆ ก็ทำเช่นนั้น Ruby และ Perl เป็นตัวอย่าง VM รู้ว่าตัวแปรถูกใช้มาก่อนหรือไม่? มันสามารถคืนค่า null ได้เสมอแทนที่จะล้มเหลวโดยมีหรือไม่มีข้อความแสดงข้อผิดพลาด และนี่ไม่ได้เกี่ยวกับ 5 ตัวอักษรที่มีหมัดมันเกี่ยวกับการเขียนparams["width"] = params["width"] || 5เพื่อตั้งค่าเริ่มต้นแทนที่จะเป็นเรื่องไร้สาระทั้งหมดด้วยการisset()โทร
vava

3
ขออภัยที่รื้อฟื้นกระทู้เก่า ข้อผิดพลาดที่เลวร้ายที่สุดสองประการของ PHP คือregister_globalsและmagic_quotes. ปัญหาเหล่านี้ทำให้ตัวแปรที่ไม่ได้เริ่มต้นดูแทบไม่เป็นอันตรายเมื่อเปรียบเทียบ
สถิติ

3

ฉันใช้ฟังก์ชันเหล่านี้

function load(&$var) { return isset($var) ? $var : null; }
function POST($var) { return isset($_POST[$var]) ? $_POST[$var] : null; }

ตัวอย่าง

$y = load($x); // null, no notice

// this attitude is both readable and comfortable
if($login=POST("login") and $pass=POST("pass")) { // really =, not ==
  // executes only if both login and pass were in POST
  // stored in $login and $pass variables
  $authorized = $login=="root" && md5($pass)=="f65b2a087755c68586568531ad8288b4";
}

2
ฉันใช้สิ่งนี้ด้วย แต่จำไว้ว่าในบางกรณีตัวแปรของคุณจะเริ่มต้นโดยอัตโนมัติเช่น load ($ array ['FOO']) จะสร้างคีย์ FOO ใน $ array
จ้า

2

ยินดีต้อนรับสู่null coalescing operator (PHP> = 7.0.1):

$field = $_GET['field'] ?? null;

PHP พูดว่า:

ตัวดำเนินการการรวมตัวเป็นโมฆะ (??) ถูกเพิ่มเป็นน้ำตาลวากยสัมพันธ์สำหรับกรณีทั่วไปที่จำเป็นต้องใช้ ternary ร่วมกับ isset () จะส่งคืนตัวถูกดำเนินการตัวแรกหากมีอยู่และไม่ใช่ NULL มิฉะนั้นจะส่งกลับตัวถูกดำเนินการที่สอง


1

สร้างฟังก์ชันที่ส่งคืนfalseหากไม่ได้ตั้งค่าและหากระบุไว้falseหากว่างเปล่า หากถูกต้องจะส่งคืนตัวแปร คุณสามารถเพิ่มตัวเลือกเพิ่มเติมได้ตามที่เห็นในโค้ดด้านล่าง:

<?php
function isset_globals($method, $name, $option = "") {
    if (isset($method[$name])) {    // Check if such a variable
        if ($option === "empty" && empty($method[$name])) { return false; } // Check if empty 
        if ($option === "stringLength" && strlen($method[$name])) { return strlen($method[$name]); }    // Check length of string -- used when checking length of textareas
        return ($method[$name]);
    } else { return false; }
}

if (!isset_globals("$_post", "input_name", "empty")) {
    echo "invalid";
} else {
    /* You are safe to access the variable without worrying about errors! */
    echo "you uploaded: " . $_POST["input_name"];
}
?>

0

ซอฟต์แวร์ไม่ได้ดำเนินการอย่างน่าอัศจรรย์โดยพระคุณของพระเจ้า หากคุณคาดหวังว่าจะมีบางสิ่งที่ขาดหายไปคุณจำเป็นต้องจัดการกับมันอย่างเหมาะสม

หากคุณเพิกเฉยแสดงว่าคุณกำลังสร้างช่องโหว่ด้านความปลอดภัยในแอปพลิเคชันของคุณ ในภาษาคงที่การเข้าถึงตัวแปรที่ไม่ได้กำหนดมันเป็นไปไม่ได้ มันจะไม่เพียงแค่คอมไพล์หรือทำให้แอปพลิเคชันของคุณพังหากเป็นโมฆะ

นอกจากนี้ยังทำให้แอปพลิเคชันของคุณไม่สามารถเข้าถึงได้และคุณจะบ้าคลั่งเมื่อสิ่งที่ไม่คาดคิดเกิดขึ้น ความเข้มงวดด้านภาษาเป็นสิ่งที่จำเป็นและ PHP โดยการออกแบบนั้นผิดในหลาย ๆ ด้าน มันจะทำให้คุณเป็นโปรแกรมเมอร์ที่ไม่ดีหากคุณไม่ทราบ


ฉันตระหนักดีถึงข้อบกพร่องของ PHP ดังที่ฉันได้ชี้ให้เห็นในคำถามฉันกำลังพูดถึงการยกเครื่องโครงการเก่า ๆ
Pekka

ตกลง การเป็นนักพัฒนา PHP ที่ใช้เวลานานมันค่อนข้างยากสำหรับฉันที่จะลงทุนในภาษาใหม่ ๆ เช่น Java ซึ่งคุณต้องประกาศทุกอย่าง
Dzhuneyt

0

ฉันไม่แน่ใจว่าคำจำกัดความของความสามารถในการอ่านของคุณคืออะไร แต่การใช้บล็อกว่าง (), isset () และ try / throw / catch อย่างเหมาะสมนั้นค่อนข้างสำคัญต่อกระบวนการทั้งหมด

หาก E_NOTICE ของคุณมาจาก $ _GET หรือ $ _POST ควรตรวจสอบค่าว่าง () พร้อมกับการตรวจสอบความปลอดภัยอื่น ๆ ทั้งหมดที่ข้อมูลนั้นควรจะต้องผ่าน

หากมาจากฟีดภายนอกหรือไลบรารีควรห่อด้วย try / catch

หากมาจากฐานข้อมูลควรตรวจสอบ $ db_num_rows () หรือเทียบเท่า

หากมาจากตัวแปรภายในควรเริ่มต้นอย่างเหมาะสม บ่อยครั้งการแจ้งเตือนประเภทนี้มาจากการกำหนดตัวแปรใหม่ให้กับการส่งคืนฟังก์ชันที่ส่งคืน FALSE เมื่อเกิดความล้มเหลว สิ่งเหล่านี้ควรรวมอยู่ในการทดสอบที่ในกรณีที่เกิดความล้มเหลวสามารถกำหนดตัวแปรเป็นค่าเริ่มต้นที่ยอมรับได้ซึ่งโค้ดสามารถจัดการได้หรือโยนข้อยกเว้นที่โค้ดสามารถจัดการได้

สิ่งเหล่านี้ทำให้โค้ดยาวขึ้นเพิ่มบล็อคพิเศษและเพิ่มการทดสอบพิเศษ แต่ฉันไม่เห็นด้วยกับคุณเพราะฉันคิดว่าพวกเขาเพิ่มมูลค่าพิเศษอย่างแน่นอน


-2

สิ่งที่เกี่ยวกับการใช้ @ดำเนินการล่ะ?

ตัวอย่างเช่น:

if(@$foo) { /* Do something */ }

คุณอาจบอกว่าสิ่งนี้ไม่ดีเพราะคุณไม่สามารถควบคุมสิ่งที่เกิดขึ้น "ภายใน" $ foo ได้ (หากเป็นการเรียกใช้ฟังก์ชันที่มีข้อผิดพลาด PHP เป็นต้น) แต่ถ้าคุณใช้เทคนิคนี้กับตัวแปรเท่านั้นสิ่งนี้จะเทียบเท่ากับ:

if(isset($foo) && $foo) { /* ... */ }

if(isset($foo))ก็เพียงพอแล้ว มันจะกลับมาถ้านิพจน์ประเมินTRUE TRUE
Dzhuneyt

2
@ ColorWP.com มันจะคืนค่า true หากนิพจน์ประเมินว่าเป็นเท็จ
Jon Hulka

คุณควรใช้พารามิเตอร์ @ (เพื่อเพิกเฉยต่อการแจ้งให้ทราบล่วงหน้า) กับโค้ดที่ไม่ได้อยู่ระหว่างการพัฒนาเพิ่มเติมหรือในโค้ดแบบครั้งเดียวหรือการแก้ไขด่วนในโครงการที่มีอยู่ซึ่งคุณไม่ต้องการแสดงให้ใครเห็นอีก แต่เป็นวิธีแก้ปัญหาทั่วไปสำหรับการแฮ็กอย่างรวดเร็ว
rubo77
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.