PHP + PDO + MySQL : MySQL의 정수 및 숫자 열을 PHP에서 정수 및 숫자로 어떻게 반환합니까?


85

이 질문이 Stack Overflow에서 몇 번 반복되는 것을 보았지만 문제를 충분히 탐구하지 못했습니다 (또는 적어도 나에게 도움이되는 방식으로)

문제는 DB 쿼리가 정수 열에 대해 PHP에서 정수 데이터 유형을 반환해야한다는 것입니다. 대신 쿼리는 모든 열을 문자열 유형으로 반환합니다.

결과가 문자열로 캐스트되지 않도록하기 위해 false 이면 "PDO :: ATTR_STRINGIFY_FETCHES" 를 확인했습니다.

내가 본 답변 :

  • 할 수 없어
    • 아니요, Mac OS X에 설치된 PHP / MySQL에서 작동합니다.
  • 코드의 모든 값을 형변환하십시오.
    • 아니, 안 할거야
  • 그것에 대해 걱정하지 마십시오. PHP는 느슨하게 입력됩니다.
    • 내 데이터는 JSON으로 출력되고 다른 많은 서비스에서 사용되며 일부는 올바른 형식의 데이터가 필요합니다.

내 연구를 통해 이것이 드라이버 구현 문제라는 것을 이해합니다.

많은 출처에서 MySQL 기본 드라이버가 숫자 유형 반환을 지원하지 않는다고 주장합니다. 이것은 Mac OS X에서 작동하기 때문에 사실이 아닌 것 같습니다. " Linux 의 MySQL 기본 드라이버가이 기능을 지원하지 않는다 "는 뜻이 아니라면 말입니다 .

이것은 내가 Mac OS X에 설치 한 드라이버 / 환경에 특별한 것이 있음을 의미합니다. 수정 사항을 적용하기 위해 차이점을 식별하려고 노력했지만 이러한 사항을 확인하는 방법에 대한 지식이 제한되어 있습니다.

차이점들:

  • OS X의 PHP는 Home Brew를 통해 컴파일 및 설치되었습니다.
  • Ubuntu의 PHP는 "apt-get install php5-dev"를 통해 설치되었습니다.
  • OS X의 PHP는 OS X에서도 실행되는 MySQL 서버에 연결됩니다.
    • 서버 버전 : 5.1.71-log 소스 배포
  • Ubuntu의 PHP가 Rackspace 클라우드 데이터베이스에 연결 중입니다.
    • 서버 버전 : 5.1.66-0 + squeeze1 (Debian)

Ubuntu 환경

  • 버전 : 10.04.1
  • PHP 5.4.21-1 + debphp.org ~ lucid + 1 (cli) (빌드 : 2013 년 10 월 21 일 08:14:37)
  • php -i

    pdo_mysql

    MySQL 용 PDO 드라이버 => 활성화 된 클라이언트 API 버전 => 5.1.72

Mac OS X 환경

  • 10.7.5
  • PHP 5.4.16 (cli) (빌드 : 2013 년 8 월 22 일 09:05:58)
  • php -i

    pdo_mysql

    MySQL 용 PDO 드라이버 => 활성화 된 클라이언트 API 버전 => mysqlnd 5.0.10-20111026-$ Id : e707c415db32080b3752b232487a435ee0372157 $

사용 된 PDO 플래그

PDO::ATTR_CASE => PDO::CASE_NATURAL,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
PDO::ATTR_STRINGIFY_FETCHES => false,
PDO::ATTR_EMULATE_PREPARES => false,

모든 도움과 전문 지식을 주시면 감사하겠습니다. :) 답을 찾으면 여기에 다시 게시 할 것입니다.


2
mysqlnd의 책임입니다. 나는 믿는다
당신의 상식

똑같은 질문이 있지만 MS SQL Server에 대한 것입니다. mysqlnd와 유사한 강력한 형식의 라이브러리가 있습니까? 최신 드라이버 내가 찾을 수있는 모든 문자열을 반환합니다.
GSerg

답변:


121

해결책은 php 용 mysqlnd 드라이버를 사용하고 있는지 확인하는 것 입니다.

mysqlnd를 사용하고 있지 않다는 것을 어떻게 알 수 있습니까?

를 볼 때 "mysqlnd"에 대한 언급 php -i없습니다 . pdo_mysql섹션는 다음과 같이해야합니다 :

pdo_mysql

PDO Driver for MySQL => enabled Client API version => 5.1.72

어떻게 설치합니까?

대부분의 L / A / M / P 설치 가이드에서 권장 apt-get install php5-mysql하지만 MySQL 용 기본 드라이버는 다른 패키지로 설치됩니다 php5-mysqlnd.. 나는 이것이 ppa : ondrej / php5-oldstable 에서 사용 가능하다는 것을 발견했습니다 . .

새 드라이버로 전환하려면 (Ubuntu에서) :

  • 이전 드라이버를 제거하십시오.
    apt-get remove php5-mysql
  • 새 드라이버 설치 :
    apt-get install php5-mysqlnd
  • apache2를 다시 시작합니다.
    service apache2 restart

드라이버가 사용 중인지 어떻게 확인합니까?

이제 섹션 php -i에서 "mysqlnd"를 명시 적으로 언급 pdo_mysql합니다.

pdo_mysql

PDO Driver for MySQL => enabled
Client API version => mysqlnd 5.0.10 - 20111026 - $Id:      e707c415db32080b3752b232487a435ee0372157 $

PDO 설정

즉 확인 PDO::ATTR_EMULATE_PREPARES이다 false(당신의 기본값을 확인하거나 설정) :
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

즉 확인 PDO::ATTR_STRINGIFY_FETCHES이다 false(당신의 기본값을 확인하거나 설정) :
$pdo->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false);

반환 된 값

  • 부동 소수점 유형 (FLOAT, DOUBLE)은 PHP 부동 소수점으로 반환됩니다.
  • 정수 유형 (INTEGER, INT, SMALLINT, TINYINT, MEDIUMINT, BIGINT †)은 PHP 정수로 반환됩니다.
  • 고정 소수점 유형 (DECIMAL, NUMERIC)은 문자열로 반환됩니다.

† 64 비트 부호있는 정수 (9223372036854775807)보다 큰 값을 가진 BIGINT는 문자열 (또는 32 비트 시스템에서는 32 비트)로 반환됩니다.

    object(stdClass)[915]
      public 'integer_col' => int 1
      public 'double_col' => float 1.55
      public 'float_col' => float 1.5
      public 'decimal_col' => string '1.20' (length=4)
      public 'bigint_col' => string '18446744073709551615' (length=20)

3
이 버전의 mysqlnd를 활성화해도 DECIMALS는 여전히 문자열로 전송됩니다 ... (FLOATS는 float로 반환됩니다!) : / 출처 : 테스트했습니다.
Pere 2014

4
또한 PDO :: ATTR_STRINGIFY_FETCHES는 그것과 아무 관련이 없습니다-시도했지만 결과에 영향을 미치지 않으며이 게시물 에서 @Josh Davis는 MySQL과 관련이 없다고 말합니다.
Pere 2014

1
감사합니다. 자세히 조사하고 DECIMAL 유형에 대한 메모를 업데이트했습니다.
stephenfrank 2014

4
@pere 이것은 올바른 행동입니다. DECIMAL은 숫자 유형이 아닙니다. 숫자에 대한 문자열 형식입니다. 따라서 반환 할 수 있습니다 : 0.30as "0.30"대신 0.3. 이 잘 동작하므로 진수는 ...이 사용됩니다
최대 Cuttins

왜 망할 타협입니까? 내가 필요로 PDO::ATTR_EMULATE_PREPARES한 번 더 한 후 명명 된 매개 변수를 사용하여
Gaby_64

4

이 대답은 효과가 있으며이 질문에 대한 Google에서 가장 인기있는 대답 인 것 같습니다. 내 문제는 여러 환경에 응용 프로그램을 배포해야하고 항상 올바른 드라이버를 설치할 수있는 능력이있는 것은 아니며 문자열이 아닌 숫자로 소수점이 필요하다는 것입니다. 그래서 JSON 인코딩 전에 대소 문자를 입력하는 루틴을 만들었습니다. 궤도에서 핵을 뚫는 것과 같습니다.

먼저 "show columns from"을 사용하여 테이블에서 열을 가져옵니다. mysql query "SHOW COLUMNS FROM table like 'colmunname'": 질문

$query = 'SHOW COLUMNS FROM ' . $table; //run with mysqli or PDO 

그런 다음 쉽게 반복 할 수 있도록 열 이름으로 인덱싱 된 배열로 형식을 가져옵니다. 표시 열의 결과 집합이 $ columns_from_table이라는 변수에 있다고 가정합니다. http://php.net/manual/en/function.array-column.php

$column_types = array_column( $columns_from_table, 'Type', 'Field');

다음으로 varchar (32) 또는 decimal (14,6)과 같은 형식에서 괄호를 제거하려고합니다.

foreach( $column_types as $col=>$type )
{
    $len = strpos( $type, '(' );
    if( $len !== false )
    {
        $column_types[ $col ] = substr( $type, 0, $len );
    }
}

이제 열 이름을 인덱스로, 형식이 지정된 유형을 값으로 사용하는 연관된 배열이 있습니다. 예를 들면 다음과 같습니다.

Array
(
    [id] => int
    [name] => varchar
    [balance] => decimal
    ...
)

이제 테이블에서 선택을 수행 할 때 결과를 반복하고 값을 적절한 유형으로 캐스트 할 수 있습니다.

foreach( $results as $index=>$row )
{
    foreach( $row as $col=>$value )
    {
        switch( $column_types[$col] )
        {
            case 'decimal':
            case 'numeric':
            case 'float':
            case 'double':

                $row[ $col ] = (float)$value;
                break;

            case 'integer':
            case 'int':
            case 'bigint':
            case 'mediumint':
            case 'tinyint':
            case 'smallint':

                $row[ $col ] = (int)$value;
                break;
        }

    }
    $results[ $index ] = $row;
}

switch 문은 적합하도록 쉽게 수정할 수 있으며 날짜 함수 등을 포함 할 수 있습니다. 예를 들어 제 경우에는 제 3자가 통화 값을 십진수로 데이터베이스에 푸시하지만 해당 데이터를 가져 와서 다음과 같이 반환해야 할 때 JSON, 문자열이 아닌 숫자 여야합니다.

PHP 7, 7.2 및 JQuery 2, 3으로 테스트되었습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.