PHP에서 형 변환 변수를 사용하는 실용적인 이유는 무엇입니까? 강력한 타이핑에 문제가

우리 대부분이 알고 있듯이 PHP는 타이핑 합니다. 그렇지 않은 사람들을 위해 PHP.net은 말합니다.

PHP는 변수 선언에서 명시 적 유형 정의를 요구하지 않거나 지원하지 않습니다. 변수 유형은 변수가 사용되는 컨텍스트에 따라 결정됩니다.

그것을 좋아하거나 미워합니다. PHP는 변수를 즉석에서 다시 캐스팅합니다. 따라서 다음 코드가 유효합니다.

$var = "10";
$value = 10 + $var;
var_dump($value); // int(20)

PHP를 사용하면 다음과 같이 변수를 명시 적으로 캐스팅 할 수 있습니다.

$var = "10";
$value = 10 + $var;
$value = (string)$value;
var_dump($value); // string(2) "20"

그것은 모두 시원합니다 …하지만, 내 삶을 위해, 나는 이것을하는 실질적인 이유를 생각할 수 없습니다.

Java와 같이 지원 언어로 강력한 타이핑에 문제가 없습니다. 괜찮습니다. 완전히 이해합니다. 또한 함수 매개 변수에서 유형 힌트 의 유용성을 알고 있으며 완전히 이해하고 있습니다.

타입 캐스팅과 관련된 문제는 위의 인용문으로 설명됩니다. PHP가 원하는대로 타입 바꿀 수 있다면 , 타입 을 강제로 캐스팅 한 후에도 그렇게 할 수 있습니다 . 그리고 그렇게 할 수 에 – 더 – 플라이 당신이 작업의 특정 유형을 필요로 할 때. 그러면 다음이 유효합니다.

$var = "10";
$value = (int)$var;
$value = $value . ' TaDa!';
var_dump($value); // string(8) "10 TaDa!"

그래서 요점이 뭐야?


PHP 에서 사용자 정의 유형 캐스팅 이 적합한 세계의 이론적 예를 보자 .

  1. 캐스트 변수 $fooint→ 로 강제 실행 (int)$foo합니다.
  2. 변수에 문자열 값을 저장하려고합니다 $foo.
  3. PHP는 예외를 던졌습니다 !! ← 말이 되겠네요. 갑자기 사용자 정의 유형 캐스팅의 이유가 존재합니다!

PHP가 필요에 따라 상황을 전환한다는 사실은 사용자 정의 유형 캐스팅의 요지를 모호하게 만듭니다. 예를 들어 다음 두 코드 샘플은 동일합니다.

// example 1
$foo = 0;
$foo = (string)$foo;
$foo = '# of Reasons for the programmer to type cast $foo as a string: ' . $foo;

// example 2
$foo = 0;
$foo = (int)$foo;
$foo = '# of Reasons for the programmer to type cast $foo as a string: ' . $foo;

원래이 질문을 한 지 1 년 후, 실제 환경에서 누가 타입 캐스팅을 사용하고 있는가? 당신은 정말입니다.

식당 메뉴를 위해 웹 사이트에 돈 가치를 표시해야했습니다. 사이트를 디자인하려면 후행 0을 다듬어야하므로 디스플레이가 다음과 같이 보입니다.

Menu Item 1 .............. $ 4
Menu Item 2 .............. $ 7.5
Menu Item 3 .............. $ 3

내가 찾은 가장 좋은 방법은 변수를 float로 캐스팅하는 것이 아닙니다.

$price = '7.50'; // a string from the database layer.
echo 'Menu Item 2 .............. $ ' . (float)$price;

PHP는 float의 후행 0을 자른 다음 float를 문자열로 다시 연결하여 연결합니다.



답변

약한 유형의 언어에서 유형 캐스팅은 유형 연산에서 모호성을 제거하기 위해 존재합니다. 그렇지 않으면 컴파일러 / 인터프리터가 순서 또는 다른 규칙을 사용하여 사용할 연산을 가정합니다.

일반적으로 PHP는이 패턴을 따르지만, 내가 확인한 사례 중 PHP는 반 직관적으로 행동했습니다.

JavaScript를 비교 언어로 사용하는 경우가 있습니다.

문자열 연결

별도의 문자열 연결 ( .)과 더하기 ( +) 연산자 가 있기 때문에 PHP에서는 문제가되지 않습니다 .

자바 스크립트

var a = 5;
var b = "10"
var incorrect = a + b; // "510"
var correct = a + Number(b); // 15

문자열 비교

컴퓨터 시스템에서 종종 “5”는 숫자로 해석되지 않으므로 “10”보다 큽니다. PHP에서는 그렇지 않습니다. 문자열 모두 문자열이지만 숫자임을 인식하고 캐스트가 필요하지 않습니다.

자바 스크립트

console.log("5" > "10" ? "true" : "false"); // true

PHP

echo "5" > "10" ? "true" : "false";  // false!

함수 서명 입력

PHP는 함수 시그니처에 대한 기본 형식 검사를 구현하지만 불행히도 사용하기가 거의 불가능합니다.

내가 잘못하고 있다고 생각했지만 문서에 대한 의견은 배열 이외의 내장 유형을 PHP 함수 서명에 사용할 수 없음을 확인합니다-오류 메시지가 잘못되었습니다.

PHP

function testprint(string $a) {
    echo $a;
}

$test = 5;
testprint((string)5); // "Catchable fatal error: Argument 1 passed to testprint()
                      //  must be an instance of string, string given" WTF?

그리고 내가 알고있는 다른 언어와 달리 이해하는 유형을 사용하더라도 null을 더 이상 해당 인수 ( must be an instance of array, null given)에 전달할 수 없습니다 . 어리 석다

부울 해석

[ 편집 ] : 이것은 새로운 것입니다. 다른 경우를 생각하고 다시 논리가 JavaScript와 반대입니다.

자바 스크립트

console.log("0" ? "true" : "false"); // True, as expected. Non-empty string.

PHP

echo "0" ? "true" : "false"; // False! This one probably causes a lot of bugs.

결론적으로, 내가 생각할 수있는 유일한 유용한 사례는 … (드럼 롤)

유형 잘림

즉, 한 유형의 값 (예 : 문자열)이 있고 다른 유형 (int)으로 해석하려고하고 해당 유형의 유효한 값 세트 중 하나가되도록하려면 다음을 수행하십시오.

$val = "test";
$val2 = "10";
$intval = (int)$val; // 0
$intval2 = (int)$val2; // 10
$boolval = (bool)$intval // false
$boolval2 = (bool)$intval2 // true
$props = (array)$myobject // associative array of $myobject's properties

나는 더 많은 가치를 포괄하는 유형으로 어떤 업 캐스트가 실제로 당신을 얻을 수 있는지 알 수 없습니다.

따라서 제안 된 타이핑 사용에 동의하지 않지만 (기본적으로 정적 타이핑을 제안 하고 있지만 유형 으로 강제 캐스팅 된 경우에만 오류가 발생하여 혼란을 초래할 수있는 모호함) 문제는 분명히 캐스팅 때문에이있다 매우 PHP에서 약간의 목적을.


답변

약한 / 강한 / 동적 / 정적 유형 개념을 혼합합니다.

PHP는 약하고 역동적이지만 문제는 동적 유형 개념에 있습니다. 즉, 변수에는 유형이 없으며 값에는 없습니다.

‘유형 캐스팅’은 원본과 다른 유형의 새로운 값을 생성하는 표현식입니다. 변수에 영향을 미치지 않습니다 (관련된 경우).

캐스트 값을 정기적으로 입력하는 상황은 숫자 SQL 매개 변수입니다. SQL 문에 삽입하는 입력 값을 삭제 / 이스케이프 처리하거나 매개 변수화 된 쿼리를 사용하는 것이 좋습니다. 그러나 정수가되어야하는 값을 원한다면 캐스팅하는 것이 훨씬 쉽습니다.

치다:

function get_by_id ($id) {
   $id = (int)$id;
   $q = "SELECT * FROM table WHERE id=$id LIMIT 1";
   ........
}

첫 줄을 생략하면 $idSQL 주입을위한 쉬운 벡터가 될 것입니다. 캐스트는 그것이 무해한 정수인지 확인합니다. SQL을 삽입하려고하면id=0


답변

내가 찾은 PHP에서 유형 캐스팅을 사용하는 한 가지 방법 :

서버에서 PHP 스크립트에 http 요청하여 데이터베이스에서 데이터를 검색하는 Android 앱을 개발 중입니다. 이 스크립트는 PHP 객체 (또는 연관 배열) 형태로 데이터를 저장하고 JSON 객체로 앱에 반환됩니다. 유형 캐스팅이 없으면 다음과 같은 내용이 표시됩니다.

{ "user" : { "id" : "1", "name" : "Bob" } }

그러나 (int)PHP 객체를 저장할 때 사용자 ID에 PHP 유형 캐스팅 을 사용하면 대신 앱으로 반환됩니다.

{ "user" : { "id" : 1, "name" : "Bob" } }

그런 다음 앱에서 JSON 객체를 구문 분석하면 ID를 정수로 구문 분석하지 않아도됩니다!

매우 유용합니다.


답변

하나의 예는 __toString 방법으로 객체이다
$str = $obj->__toString();
$str = (string) $obj;. 두 번째는 타이핑이 훨씬 적으며, 구두점은 입력 시간이 오래 걸립니다. 또한 다른 사람들이 동의하지 않을 수도 있지만 더 읽기 쉽다고 생각합니다.

또 다른 하나의 요소의 배열을하고있다 :
array($item);(array) $item;. 이렇게하면 스칼라 유형 (정수, 자원 등)이 배열 안에 배치됩니다.
선택적 $item으로 객체 인 경우 속성이 해당 값의 키가됩니다. 그러나 객체-> 배열 변환은 약간 이상하다고 생각합니다. 개인 속성과 보호 속성은 배열의 일부이며 이름이 바뀝니다. PHP 문서 를 인용하려면 : 개인 변수는 클래스 이름 앞에 변수 이름이 붙습니다. 보호 된 변수는 변수 이름 앞에 ‘*’가 붙습니다.

또 다른 용도는 GET / POST 데이터를 데이터베이스에 적합한 유형으로 변환하는 것입니다. MySQL 은이 자체를 처리 할 수 ​​있지만 더 ANSI 호환 서버는 데이터를 거부 할 수 있다고 생각합니다. 내가 데이터베이스에 대해서만 언급하는 이유는 대부분의 다른 경우 데이터가 특정 시점에 유형에 따라 작업을 수행하기 때문입니다 (즉, int / float는 일반적으로 데이터베이스에서 계산을 수행하는 등).


답변

이 스크립트는 :

$tags = _GET['tags'];
foreach ($tags as $tag) {
    echo 'tag: ', $tag;
}

첫 번째 경우에는 배열을 반환하지만 두 번째는 아닌 배열을 반환 하기 때문에 script.php?tags[]=one제대로 실행 되지만 실패합니다 . 스크립트는 배열을 예상하도록 작성되었으므로 (스크립트로 전송되는 쿼리 문자열에 대한 제어력이 적음) 다음에서 결과를 적절히 캐스팅하여 문제를 해결할 수 있습니다 .script.php?tags=one_GET['tags']_GET

$tags = (array) _GET['tags'];
foreach ($tags as $tag) {
    echo 'tag: ', $tag;
}

답변

또한 신뢰할 수없는 데이터가 문제를 일으키지 않도록하기 위해 빠르고 더러운 방법으로 사용될 수도 있습니다.

$amount = (float) $_POST['amount'];

if( $amount > 0 ){
    $remoteService->doacalculationwithanumber( $amount );    
}

분명히 이것은 if 문에서 비교 연산자에 의해 결함이 있고 암시 적으로 처리되지만 코드가 무엇을하는지 정확히 알 수 있도록 도와줍니다.


답변

자주 사용하는 PHP 리 캐스팅 변수의 “사용”중 하나는 외부 소스 (사용자 입력 또는 데이터베이스)에서 데이터를 검색 할 때입니다. 이를 통해 코더 (개발자에게 말하지 않았 음 )는 다른 소스에서 사용 가능한 여러 데이터 유형을 무시 (또는 배우지 못함) 할 수 있습니다.

내가 상속하고 여전히 유지하는 코드를 가진 한 코더 (개발자 에게 말하지 않았다는 점에 유의) 슈퍼 변수에 반환 된 문자열 "20"$_GET20 + 20 추가 할 때 정수 연산 사이에 차이있음 을 알지 못하는 것 같습니다 데이터베이스의 값 그녀는 PHP가 .문자열 연결에 사용 +하고 다른 모든 언어 와 달리 사용하는 것이 운이 좋다 . 왜냐하면 그녀의 코드가 두 개의 문자열 ( varcahrMySQL과 a 값 $_GET)을 추가하고 int를 얻었 기 때문이다.

이것이 실제적인 예입니까? 코더가 작업하는 데이터 유형을 모른 채로 벗어날 수 있다는 의미에서만. 나는 개인적으로 그것을 싫어한다.