code

isset () 및 empty ()를 피하는 방법

codestyles 2020. 8. 25. 08:03
반응형

isset () 및 empty ()를 피하는 방법


E_NOTICE 오류 수준에서 실행할 때 많은 "xyz is undefined"및 "undefined offset"메시지를 던지는 이전 응용 프로그램이 여러 개 있습니다. 왜냐하면 변수의 존재는 isset()and consorts를 사용하여 명시 적으로 확인하지 않기 때문 입니다.

누락 된 변수 또는 오프셋에 대한 알림이 생명의 은인이 될 수 있고, 약간의 성능 향상을 얻을 수 있으며, 전체적으로 더 깔끔한 방식이므로 E_NOTICE와 호환되도록 작업하는 것을 고려하고 있습니다.

그러나 수백 개의 isset() empty()array_key_exists()s가 내 코드에 미치는 영향이 마음에 들지 않습니다 . 가치 나 의미의 측면에서 아무것도 얻지 못하고 부풀어지고 가독성이 떨어집니다.

변수 검사를 초과하지 않고 E_NOTICE와 호환되는 코드를 어떻게 구성 할 수 있습니까?


관심있는 분들을 위해이 주제를 작은 기사로 확장했습니다. 아래 정보는 좀 더 구조화 된 형식으로 제공됩니다. The Definitive Guide To PHP isset And empty


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는 무언가를 의미 하려는 써드 파티 라이브러리 일 것입니다. 그러나 nullPHP에서 감지하기가 너무 어렵 기 때문에 아직 이것을 수행하는 라이브러리를 찾지 못했습니다.


그것에 대한 함수를 작성하십시오. 다음과 같은 것 :

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()과에 이렇게.


이 문제를 해결하는 가장 좋은 방법 중 하나는 클래스를 통해 GET 및 POST (COOKIE, SESSION 등) 배열의 값에 액세스하는 것입니다.

Create a class for each of those arrays and declare __get and __set methods (overloading). __get accepts one argument which will be the name of a value. This method should check this value in the corresponding global array either using isset() or empty() and return the value if it exists or null (or some other default value) otherwise.

After that you can confidently access array values in this manner: $POST->username and do any validation if needed without using any isset()s or empty()s. If username does not exist in the corresponding global array then null will be returned, so no warnings or notices will be generated.


I don't mind using the array_key_exists(), in fact I prefer using this specific function rather than relying on hack functions which may change their behavior in the future like empty and isset (strikedthrough to avoid susceptibilities).


I do however, use a simple function that comes handy in this, and some other situations in dealing with array indexes:

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;
}

Let's say you've the following arrays:

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

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

How do you get the "value" out of the arrays? Simple:

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');

We already have uni and multi-dimensional arrays covered, what else can we possibly do?


Take the following piece of code for instance:

$url = 'https://stackoverflow.com/questions/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';
}

Pretty boring isn't it? Here is another approach using the Value() function:

$url = 'https://stackoverflow.com/questions/1960509';
$domain = Value(parse_url($url), 'host', 'N/A');

As an additional example, take the RealIP() function for a test:

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

Neat, huh? ;)


I'm here with you. But PHP designers has made a lot more worse mistakes than that. Short of defining custom function for any value reading, there's no way around it.


I use these function

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

Examples

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

// this attitude is both readable and comfortable
if($login=POST("login")) // really =, not ==
if($pass=POST("pass"))
if($login=="Admin" && $pass==...) {
  // login and pass are not empty, login is "Admin" and pass is ...
  $authorized = true;
  ...
}

Welcome to Null coalescing operator (PHP >= 7.0.1):

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

PHP says:

The null coalescing operator (??) has been added as syntactic sugar for the common case of needing to use a ternary in conjunction with isset(). It returns its first operand if it exists and is not NULL; otherwise it returns its second operand.


Make a function which returns false if not set, and, if specified, false if empty. If valid it returns the variable. You can add more options as seen in the code below:

<?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"];
}
?>

I'm not sure what your definition of readability is, but proper use of empty(), isset() and try/throw/catch blocks, is pretty important to the whole process. If your E_NOTICE is coming from $_GET or $_POST, then they should be checked against empty() right along with all the other security checks that that data should have to pass. If it's coming from external feeds or libraries, it should be wrapped in try/catch. If it's coming from the database, $db_num_rows() or it's equivalent should be checked. If it's coming from internal variables, they should be properly initialized. Often, these types of notices come from assigning a new variable to the return of a function that returns FALSE on a failure, those should be wrapped in a test that, in the event of a failure, can either assign the variable an acceptable default value that the code can handle, or throwing an exception that the code can handle. These things make the code longer, add extra blocks, and add extra tests, but I disagree with you in that I think they most definitely add extra value.


software does not magically run by the grace of god, if you are expecting something that is missing you need to properly handle it. if you ignore it you are probably creating security holes in your applications. on static languages accessing a non-defined variable is just not possible, it won't simply compile or crash your application if it's null. furthermore makes your application unmaintainable, and you are going to go mad when unexpected things happen. language strictness is a must and php, by design, is wrong in so many aspects. it will make you a bad programmer if you are not aware.


What about using the @ operator ? e.g.:

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

You may say this is bad because you have no control on what happens "inside" $foo (if it was a function call that contains a PHP error for example) but if you only use this technique for variables, this is equivalent to:

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

참고URL : https://stackoverflow.com/questions/1960509/how-to-avoid-isset-and-empty

반응형