PHP + PDO + MySQL:MySQLから整数列と数値列をPHPの整数と数値として返すにはどうすればよいですか?


85

Stack Overflowでこの質問が数回繰り返されているのを見たことがありますが、問題を十分に調査するものはありません(または、少なくとも私に役立つ方法で)

問題は、DBクエリが整数列に対してPHPで整数データ型を返す必要があることです。代わりに、クエリはすべての列を文字列型として返します。

「PDO :: ATTR_STRINGIFY_FETCHES」の場合は、 結果が文字列にキャストされていないことを確認するために falseのを確認しました。

私が見た答え:

  • できません
    • いいえ、Mac OSXでインストールされたPHP / MySQLで動作します
  • コード内のすべての値を型キャストします
    • いいえ、私はそれをしません
  • 心配しないでください、PHPは大まかに型付けされています
    • 私のデータはJSONとして出力され、他の多くのサービスによって消費されます。正しい形式のデータが必要なものもあります。

私の調査から、これはドライバーの実装の問題であることがわかりました。

多くの情報源は、MySQLネイティブドライバーが数値型を返すことをサポートしていないと主張しています。Mac OS Xで動作するため、これは当てはまらないようです。「Linux上のMySQLネイティブドライバはこの機能をサポートしていない」と言わない限り。

これは、Mac OS Xにインストールしたドライバー/環境に何か特別なものがあることを意味します。修正を適用するために違いを特定しようとしていますが、これらを確認する方法の知識に制限があります。

違い:

  • OS X上のPHPは、HomeBrewを介してコンパイルおよびインストールされました。
  • Ubuntu上のPHPは、「apt-getinstallphp5-dev」を介してインストールされました
  • OS X上のPHPは、OSX上でも実行されているMySQLサーバーに接続しています
    • サーバーバージョン:5.1.71-ログソース配布
  • 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 OSX環境

  • 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 SQLServerについてです。mysqlndに似た、そのための強く型付けされたライブラリはありますか?最新のドライバ私は見つけることができるが、すべての文字列を返します。
GSerg 2016年

回答:


120

解決策は、php用のmysqlndドライバーを使用していることを確認することです。

mysqlndを使用していないことをどのように知っていますか?

を表示php -iすると、「mysqlnd」についての言及はありません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で、pdo_mysqlセクションで「mysqlnd」について明示的に言及します。

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ビットsignedint(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として返されます!):/出典:テストしました。
ペレ2014年

4
また、PDO :: ATTR_STRINGIFY_FETCHESはそれとは何の関係もないことにも注意してください-私が試したところ、結果には影響しません。この投稿では、ユーザー@JoshDavisがMySQLとは無関係であると述べています。
ペレ2014年

1
おかげで、私はさらに調査し、DECIMALタイプに関するメモで更新しました。
stephenfrank 2014年

4
@pereこれは正しい動作です。DECIMALは数値型ではありません。数値の文字列形式です。だから、返すことができます0.30として"0.30"の代わりに0.3。これには10進数が使用されます...したがって、これは正しい動作です
Max Cuttins 2018年

なぜそれはひどい妥協ですか?PDO::ATTR_EMULATE_PREPARES名前付きパラメーターを複数回使用する必要があります
Gaby_ 6419

4

この受け入れられた回答は機能し、この質問に対するGoogleで最も人気のある回答のようです。私の問題は、アプリケーションを複数の環境にデプロイする必要があり、適切なドライバーをインストールする機能が常にあるとは限らないことです。さらに、小数は文字列ではなく数値である必要があります。そこで、JSONエンコーディングの前に活字ケースを入力するルーチンを作成しました。これは簡単に変更できます。それは軌道からそれを核兵器にするようなものです。

まず、「show columns from」を使用して、テーブルから列を取得します。mysqlクエリ "SHOW COLUMNS FROM table like'colmunname '":questions

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

次に、列名でインデックス付けされた配列に型を取得して、反復を容易にします。showcolumnsからの結果セットが$ 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ステートメントは、それに合わせて簡単に変更でき、日付関数などを含めることができます。たとえば、私の場合、サードパーティが通貨値を10進数としてデータベースにプッシュしていますが、そのデータを取得して次のように返す必要がある場合JSON、文字列ではなく数字にする必要があります。

PHP 7、7.2およびJQuery 2、3でテスト済み。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.