php - هل يمكنني ربط مصفوفة بشرط IN()؟



arrays pdo prepared-statement where-in (18)

أنا فضولي لمعرفة ما إذا كان من الممكن ربط صفيف من القيم لعنصر نائب باستخدام PDO. تحاول حالة الاستخدام هنا تمرير صفيف من القيم للاستخدام مع شرط IN() .
أنا لست جيدًا جدًا في التوضيح ، لذلك إليك بعض psuedocode للتوضيح. أود أن أكون قادرًا على فعل شيء كالتالي:

<?php
$ids=array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN(:an_array)'
);
$stmt->bindParam('an_array',$ids);
$stmt->execute();
?>

ويكون ربط PDO واقتبس جميع القيم في الصفيف.

في هذه اللحظة أفعل:

<?php
$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
foreach($ids as &$val)
    $val=$db->quote($val); //iterate through array and quote
$in = implode(',',$ids); //create comma separated list
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN('.$in.')'
);
$stmt->execute();
?>

ما هي المهمة بالتأكيد ، ولكن أتساءل فقط إذا كان هناك حل مضمّن؟


Answers

بما أنني أقوم بالكثير من الاستعلامات الديناميكية ، فهذه وظيفة مساعد بسيطة للغاية قمت بها.

public static function bindParamArray($prefix, $values, &$bindArray)
{
    $str = "";
    foreach($values as $index => $value){
        $str .= ":".$prefix.$index.",";
        $bindArray[$prefix.$index] = $value;
    }
    return rtrim($str,",");     
}

استخدمه على النحو التالي:

$bindString = helper::bindParamArray("id", $_GET['ids'], $bindArray);
$userConditions .= " AND users.id IN($bindString)";

تقوم بإرجاع سلسلة :id1,:id2,:id3 وتحديث $bindArray الخاص بك من الارتباطات التي ستحتاجها عندما يحين وقت تشغيل الاستعلام الخاص بك. سهل!


من غير الممكن استخدام مصفوفة كهذه في PDO.

تحتاج إلى إنشاء سلسلة بمعلمة (أو تستخدم؟) لكل قيمة ، على سبيل المثال:

:an_array_0, :an_array_1, :an_array_2, :an_array_3, :an_array_4, :an_array_5

إليك مثال على ذلك:

<?php
$ids = array(1,2,3,7,8,9);
$sqlAnArray = join(
    ', ',
    array_map(
        function($index) {
            return ":an_array_$index";
        },
        array_keys($ids)
    )
);
$db = new PDO(
    'mysql:dbname=mydb;host=localhost',
    'user',
    'passwd'
);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN('.$sqlAnArray.')'
);
foreach ($ids as $index => $id) {
    $stmt->bindValue("an_array_$index", $id);
}

إذا كنت ترغب في الاستمرار في استخدام bindParam ، فيمكنك القيام بذلك بدلاً من ذلك:

foreach ($ids as $index => $id) {
    $stmt->bindParam("an_array_$index", $ids[$id]);
}

إذا كنت ترغب في استخدامها ? العناصر النائبة ، قد تفعل ذلك على النحو التالي:

<?php
$ids = array(1,2,3,7,8,9);
$sqlAnArray = '?' . str_repeat(', ?', count($ids)-1);
$db = new PDO(
    'mysql:dbname=dbname;host=localhost',
    'user',
    'passwd'
);
$stmt = $db->prepare(
    'SELECT *
     FROM phone_number_lookup
     WHERE country_code IN('.$sqlAnArray.')'
);
$stmt->execute($ids);

إذا كنت لا تعرف ما إذا كانت $ids فارغة ، فيجب اختبارها ومعالجة هذه الحالة وفقًا لذلك (إعادة مصفوفة فارغة ، أو إرجاع كائن Null ، أو رمي استثناء ، ...).


ما قاعدة البيانات التي تستخدمها؟ في PostgreSQL أحب استخدام أي (مجموعة). لذلك لإعادة استخدام المثال الخاص بك:

<?php
$ids=array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id = ANY (:an_array)'
);
$stmt->bindParam('an_array',$ids);
$stmt->execute();
?>

للأسف هذا غير محمول.

في قواعد البيانات الأخرى ، ستحتاج إلى تكوين سحرك الخاص كما ذكر آخرون. ستحتاج إلى وضع هذا المنطق في فئة / وظيفة لجعلها قابلة لإعادة الاستخدام طوال البرنامج بالطبع. إلقاء نظرة على التعليقات على صفحة mysql_query على PHP.NET لمزيد من الأفكار حول هذا الموضوع وأمثلة على هذا السيناريو.


هنا هو الحل الخاص بي. لقد قمت بتمديد فئة PDO أيضًا:

class Db extends PDO
{

    /**
     * SELECT ... WHERE fieldName IN (:paramName) workaround
     *
     * @param array  $array
     * @param string $prefix
     *
     * @return string
     */
    public function CreateArrayBindParamNames(array $array, $prefix = 'id_')
    {
        $newparams = [];
        foreach ($array as $n => $val)
        {
            $newparams[] = ":".$prefix.$n;
        }
        return implode(", ", $newparams);
    }

    /**
     * Bind every array element to the proper named parameter
     *
     * @param PDOStatement $stmt
     * @param array        $array
     * @param string       $prefix
     */
    public function BindArrayParam(PDOStatement &$stmt, array $array, $prefix = 'id_')
    {
        foreach($array as $n => $val)
        {
            $val = intval($val);
            $stmt -> bindParam(":".$prefix.$n, $val, PDO::PARAM_INT);
        }
    }
}

فيما يلي استخدام نموذج للرمز أعلاه:

$idList = [1, 2, 3, 4];
$stmt = $this -> db -> prepare("
  SELECT
    `Name`
  FROM
    `User`
  WHERE
    (`ID` IN (".$this -> db -> CreateArrayBindParamNames($idList)."))");
$this -> db -> BindArrayParam($stmt, $idList);
$stmt -> execute();
foreach($stmt as $row)
{
    echo $row['Name'];
}

اسمحوا لي أن أعرف ما هو رأيك


طريقة نظيفة جدا ل postgres تستخدم صفيف postgres ("{}"):

$ids = array(1,4,7,9,45);
$param = "{".implode(', ',$ids)."}";
$cmd = $db->prepare("SELECT * FROM table WHERE id = ANY (?)");
$result = $cmd->execute(array($param));

لشيء سريع:

//$db = new PDO(...);
//$ids = array(...);

$qMarks = str_repeat('?,', count($ids) - 1) . '?';
$sth = $db->prepare("SELECT * FROM myTable WHERE id IN ($qMarks)");
$sth->execute($ids);

أعتقد أن "سيلفرميج" على حق. سيكون عليك بناء سلسلة الاستعلام.

<?php
$ids     = array(1, 2, 3, 7, 8, 9);
$inQuery = implode(',', array_fill(0, count($ids), '?'));

$db = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN(' . $inQuery . ')'
);

// bindvalue is 1-indexed, so $k+1
foreach ($ids as $k => $id)
    $stmt->bindValue(($k+1), $id);

$stmt->execute();
?>

الإصلاح: دان ، كنت على حق. إصلاح الكود (لم تختبره)

تحرير: اقترح كل من كريس (التعليقات) و somebodyisintrouble أن foreach-loop ...

(...)
// bindvalue is 1-indexed, so $k+1
foreach ($ids as $k => $id)
    $stmt->bindValue(($k+1), $id);

$stmt->execute();

... قد تكون زائدة عن الحاجة ، لذلك يمكن استبدال حلقة foreach و $stmt->execute فقط ...

<?php 
  (...)
  $stmt->execute($ids);
?>

(مرة أخرى ، لم أختبره)


هل من المهم جدًا استخدام عبارة IN ؟ حاول استخدام FIND_IN_SET المرجع.

على سبيل المثال ، هناك استعلام في الشركة مثل ذلك

SELECT * FROM table WHERE FIND_IN_SET(id, :array)

ثم تحتاج فقط إلى ربط صفيف من القيم ، بفواصل مع فاصلة ، مثل هذا

$ids_string = implode(',', $array_of_smth); // WITHOUT WHITESPACES BEFORE AND AFTER THE COMMA
$stmt->bindParam('array', $ids_string);

وانتهى

محدث: كما أشار بعض الناس في التعليقات على هذا الجواب ، هناك بعض القضايا التي ينبغي ذكرها بشكل خارق.

  1. لا يستخدم FIND_IN_SET الفهرس في جدول ، ولا يزال غير مطبق حتى الآن - راجع هذا السجل في أداة تتبع الأخطاء MYSQL . بفضلBillKarwin للإشعار.
  2. لا يمكنك استخدام سلسلة بفاصلة بداخله كقيمة لصفيف للبحث. من المستحيل تحليل مثل هذه السلسلة في الطريق الصحيح بعد implode لأنك تستخدم رمز الفاصلة كفاصل. بفضلVaL للملاحظة.

في حالة جيدة ، إذا كنت لا تعتمد بشكل كبير على الفهارس ولا تستخدم السلاسل باستخدام فاصلة للبحث ، سيكون حلّي أسهل وأبسط وأسرع من الحلول المذكورة أعلاه.


أدرك أيضًا أن هذا الخيط قديم ولكني واجهت مشكلة فريدة من حيث ، أثناء تحويل برنامج تشغيل mysql الذي تم إيقافه قريبًا إلى برنامج تشغيل PDO ، كان علي أن أصنع وظيفة يمكن أن تبني ديناميكيًا كلا من المعلمات العادية و INs من نفس مجموعة المعلمة. لذلك بنيت بسرعة هذا:

/**
 * mysql::pdo_query('SELECT * FROM TBL_WHOOP WHERE type_of_whoop IN :param AND siz_of_whoop = :size', array(':param' => array(1,2,3), ':size' => 3))
 *
 * @param $query
 * @param $params
 */
function pdo_query($query, $params = array()){

    if(!$query)
        trigger_error('Could not query nothing');

    // Lets get our IN fields first
    $in_fields = array();
    foreach($params as $field => $value){
        if(is_array($value)){
            for($i=0,$size=sizeof($value);$i<$size;$i++)
                $in_array[] = $field.$i;

            $query = str_replace($field, "(".implode(',', $in_array).")", $query); // Lets replace the position in the query string with the full version
            $in_fields[$field] = $value; // Lets add this field to an array for use later
            unset($params[$field]); // Lets unset so we don't bind the param later down the line
        }
    }

    $query_obj = $this->pdo_link->prepare($query);
    $query_obj->setFetchMode(PDO::FETCH_ASSOC);

    // Now lets bind normal params.
    foreach($params as $field => $value) $query_obj->bindValue($field, $value);

    // Now lets bind the IN params
    foreach($in_fields as $field => $value){
        for($i=0,$size=sizeof($value);$i<$size;$i++)
            $query_obj->bindValue($field.$i, $value[$i]); // Both the named param index and this index are based off the array index which has not changed...hopefully
    }

    $query_obj->execute();

    if($query_obj->rowCount() <= 0)
        return null;

    return $query_obj;
}

لا يزال غير اختبار ولكن المنطق يبدو أنه موجود.

آمل أن يساعد شخص ما في نفس الموقف ،

تحرير: بعد بعض الاختبارات اكتشفت:

  • لا تحب شركة "." في أسمائهم (وهو غبي نوعا ما إذا سألتني)
  • bindParam هي الدالة الخاطئة ، bindValue هي الوظيفة الصحيحة.

قانون تحريرها إلى إصدار العمل.


بالنسبة لي ، فإن الحل الجنسي هو إنشاء مجموعة ارتباطية ديناميكية واستخدامها

// a dirty array sent by user
$dirtyArray = ['Cecile', 'Gilles', 'Andre', 'Claude'];

// we construct an associative array like this
// [ ':name_0' => 'Cecile', ... , ':name_3' => 'Claude' ]
$params = array_combine(
    array_map(
        // construct param name according to array index
        function ($v) {return ":name_{$v}";},
        // get values of users
        array_keys($dirtyArray)
    ),
    $dirtyArray
);

// construct the query like `.. WHERE name IN ( :name_1, .. , :name_3 )`
$query = "SELECT * FROM user WHERE name IN( " . implode(",", array_keys($params)) . " )";
// here we go
$stmt  = $db->prepare($query);
$stmt->execute($params);

أخذته إلى أبعد قليلاً للحصول على الإجابة أقرب إلى السؤال الأصلي لاستخدام العناصر النائبة لربط المعلمات.

سيكون لهذه الإجابة لجعل اثنين من الحلقات من خلال المصفوفة لاستخدامها في الاستعلام. ولكنه يعمل على حل مشكلة الحصول على عناصر نائبة للعمود للحصول على استعلامات أكثر انتقائية.

//builds placeholders to insert in IN()
foreach($array as $key=>$value) {
    $in_query = $in_query . ' :val_' . $key . ', ';
}

//gets rid of trailing comma and space
$in_query = substr($in_query, 0, -2);

$stmt = $db->prepare(
    "SELECT *
     WHERE id IN($in_query)";

//pind params for your placeholders.
foreach ($array as $key=>$value) {
    $stmt->bindParam(":val_" . $key, $array[$key])
}

$stmt->execute();

هنا هو الحل الخاص بي:

$total_items = count($array_of_items);
$question_marks = array_fill(0, $total_items, '?');
$sql = 'SELECT * FROM foo WHERE bar IN (' . implode(',', $question_marks ). ')';

$stmt = $dbh->prepare($sql);
$stmt->execute(array_values($array_of_items));

لاحظ استخدام array_values. يمكن أن يؤدي ذلك إلى إصلاح مشكلات الطلب الرئيسية.

كنت أدمج مصفوفات معرفات ، ثم أزلت عناصر مكررة. كان لدي شيء مثل:

$ids = array(0 => 23, 1 => 47, 3 => 17);

وكان هذا الفشل.


لقد قمت بتوسيع شركة تنمية نفط عمان للقيام بشيء مماثل لما تقترحه ، كما كان الأمر أسهل بالنسبة لي على المدى الطويل:

class Array_Capable_PDO extends PDO {
    /**
     * Both prepare a statement and bind array values to it
     * @param string $statement mysql query with colon-prefixed tokens
     * @param array $arrays associatve array with string tokens as keys and integer-indexed data arrays as values 
     * @param array $driver_options see php documention
     * @return PDOStatement with given array values already bound 
     */
    public function prepare_with_arrays($statement, array $arrays, $driver_options = array()) {

        $replace_strings = array();
        $x = 0;
        foreach($arrays as $token => $data) {
            // just for testing...
            //// tokens should be legit
            //assert('is_string($token)');
            //assert('$token !== ""');
            //// a given token shouldn't appear more than once in the query
            //assert('substr_count($statement, $token) === 1');
            //// there should be an array of values for each token
            //assert('is_array($data)');
            //// empty data arrays aren't okay, they're a SQL syntax error
            //assert('count($data) > 0');

            // replace array tokens with a list of value tokens
            $replace_string_pieces = array();
            foreach($data as $y => $value) {
                //// the data arrays have to be integer-indexed
                //assert('is_int($y)');
                $replace_string_pieces[] = ":{$x}_{$y}";
            }
            $replace_strings[] = '('.implode(', ', $replace_string_pieces).')';
            $x++;
        }
        $statement = str_replace(array_keys($arrays), $replace_strings, $statement);
        $prepared_statement = $this->prepare($statement, $driver_options);

        // bind values to the value tokens
        $x = 0;
        foreach($arrays as $token => $data) {
            foreach($data as $y => $value) {
                $prepared_statement->bindValue(":{$x}_{$y}", $value);
            }
            $x++;
        }

        return $prepared_statement;
    }
}

يمكنك استخدامه على النحو التالي:

$db_link = new Array_Capable_PDO($dsn, $username, $password);

$query = '
    SELECT     *
    FROM       test
    WHERE      field1 IN :array1
     OR        field2 IN :array2
     OR        field3 = :value
';

$pdo_query = $db_link->prepare_with_arrays(
    $query,
    array(
        ':array1' => array(1,2,3),
        ':array2' => array(7,8,9)
    )
);

$pdo_query->bindValue(':value', '10');

$pdo_query->execute();

تحرير قليلا عن رمز Schnalle

<?php
$ids     = array(1, 2, 3, 7, 8, 9);
$inQuery = implode(',', array_fill(0, count($ids)-1, '?'));

$db   = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN(' . $inQuery . ')'
);

foreach ($ids as $k => $id)
    $stmt->bindValue(($k+1), $id);

$stmt->execute();
?>

//implode(',', array_fill(0, count($ids)-1), '?')); 
//'?' this should be inside the array_fill
//$stmt->bindValue(($k+1), $in); 
// instead of $in, it should be $id

عندما يكون لديك معلمة أخرى ، يمكنك فعل هذا:

$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
$query = 'SELECT *
            FROM table
           WHERE X = :x
             AND id IN(';
$comma = '';
for($i=0; $i<count($ids); $i++){
  $query .= $comma.':p'.$i;       // :p0, :p1, ...
  $comma = ',';
}
$query .= ')';

$stmt = $db->prepare($query);
$stmt->bindValue(':x', 123);  // some value
for($i=0; $i<count($ids); $i++){
  $stmt->bindValue(':p'.$i, $ids[$i]);
}
$stmt->execute();

قمت بتعيين عدد لأول مرة من "؟" في الاستعلام ثم عن طريق "for" إرسال المعلمات مثل هذا:

require 'dbConnect.php';
$db=new dbConnect();
$array=[];
array_push($array,'value1');
array_push($array,'value2');
$query="SELECT * FROM sites WHERE kind IN (";

foreach ($array as $field){
    $query.="?,";
}
$query=substr($query,0,strlen($query)-1);
$query.=")";
$tbl=$db->connection->prepare($query);
for($i=1;$i<=count($array);$i++)
    $tbl->bindParam($i,$array[$i-1],PDO::PARAM_STR);
$tbl->execute();
$row=$tbl->fetchAll(PDO::FETCH_OBJ);
var_dump($row);

لم يعمل حل من EvilRygy بالنسبة لي. في Postgres ، يمكنك تنفيذ حل بديل آخر:


$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id = ANY (string_to_array(:an_array, ','))'
);
$stmt->bindParam(':an_array', implode(',', $ids));
$stmt->execute();

مقدمة

منذ أن قضيت دراستي الجامعية ، قمت ببرمجة في Java ، و JavaScript ، و Pascal ، و ABAP ، و PHP ، و Progress 4GL ، و C / C ++ ، وربما بعض اللغات الأخرى التي لا أستطيع التفكير بها الآن.

في حين أن جميعهم لديهم خصوصيات لغوية خاصة بهم ، فإن كل لغة من هذه اللغات تتشارك في العديد من المفاهيم الأساسية نفسها. تتضمن هذه المفاهيم الإجراءات / الدالات ، IF -statements ، FOR -lops ، و WHILE -loops.

التقليدية لقلوب

تحتوي الحلقة التقليدية for ثلاثة مكونات:

  1. التهيئة: يتم تنفيذها قبل تنفيذ كتلة المظهر في المرة الأولى
  2. الشرط: يتحقق من الشرط في كل مرة قبل تنفيذ كتلة الحلقة ، ويتم إنهاء الحلقة إذا كانت خاطئة
  3. المفكرة المتأخرة: يتم تنفيذها في كل مرة بعد تنفيذ كتلة الحلقة

هذه المكونات الثلاثة مفصولة عن بعضها البعض بـ: رمز. يعد المحتوى لكل مكون من هذه المكونات الثلاثة اختياريًا ، مما يعني أن ما يلي هو الحد الأدنى للحلقة الممكنة:

for (;;) {
    // Do stuff
}

بالطبع ، سوف تحتاج إلى تضمين if(condition === true) { break; } if(condition === true) { break; } أو if(condition === true) { return; } if(condition === true) { return; } مكان ما داخل ذلك -للحصول على إيقاف تشغيله.

عادة ، على الرغم من ذلك ، يتم استخدام التهيئة للإعلان عن فهرس ، يتم استخدام الشرط للمقارنة بين هذا الفهرس مع قيمة الحد الأدنى أو الحد الأقصى ، ويتم استخدام المفكرات التالية لزيادة الفهرس:

for (var i = 0, length = 10; i < length; i++) {
    console.log(i);
}

استخدام حلقة تقليدية للحلقة عبر صفيف

الطريقة التقليدية للحلقة عبر صفيف ، هي:

for (var i = 0, length = myArray.length; i < length; i++) {
    console.log(myArray[i]);
}

أو ، إذا كنت تفضل التكرار إلى الخلف ، فيمكنك إجراء ذلك:

for (var i = myArray.length - 1; i > -1; i--) {
    console.log(myArray[i]);
}

ومع ذلك ، هناك العديد من الاختلافات الممكنة ، على سبيل المثال ، هذه الاختلافات:

for (var key = 0, value = myArray[key], length = myArray.length; key < length; value = myArray[++key]) {
    console.log(value);
}

... ما سر جديدة هذا ...

var i = 0, length = myArray.length;
for (; i < length;) {
    console.log(myArray[i]);
    i++;
}

... ما سر جديدة هذا:

var key = 0, value;
for (; value = myArray[key++];){
    console.log(value);
}

أيهما أفضل يعمل هو إلى حد كبير مسألة الذوق الشخصي وحالة الاستخدام المحددة التي تنفذها.

لاحظ أن كل هذه الأشكال تدعمها جميع المتصفحات ، بما في ذلك المتصفحات القديمة جدًا!

حلقة في while

بديل واحد للحلقة هو حلقة في while . للحلقة عبر صفيف ، يمكنك القيام بذلك:

var key = 0;
while(value = myArray[key++]){
    console.log(value);
}

مثل التقليدية للحلقات ، في while الحلقات تدعمها حتى أقدم المتصفحات.

لاحظ أيضًا أنه في كل مرة يمكن إعادة كتابة حلقة كـ حلقة for . على سبيل المثال ، تتصرف حلقة while hereabove بالطريقة نفسها تمامًا مثل: tololoove:

for(var key = 0; value = myArray[key++];){
    console.log(value);
}

For...in for...of

في JavaScript ، يمكنك أيضًا القيام بذلك:

for (i in myArray) {
    console.log(myArray[i]);
}

ومع ذلك ، يجب استخدام هذا بعناية ، حيث أنه لا يتصرف بنفس الطريقة التقليدية في جميع الحالات ، وهناك آثار جانبية محتملة يجب أخذها بعين الاعتبار. راجع لماذا يستخدم "for ... in" مع تكوين الصفيف فكرة سيئة؟ لمزيد من التفاصيل.

كبديل for...in ، هناك الآن أيضا من https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of . يوضح المثال التالي الفرق بين a for...of loop و for...in حلقة:

var myArray = [3, 5, 7];
myArray.foo = "hello";

for (var i in myArray) {
  console.log(i); // logs 0, 1, 2, "foo"
}

for (var i of myArray) {
  console.log(i); // logs 3, 5, 7
}

بالإضافة إلى ذلك ، يجب الأخذ في الاعتبار أنه لا يوجد إصدار من Internet Explorer يدعم for...of ( الحافة 12+ لا) ويتطلب ذلك في ما لا يقل عن Internet Explorer 10.

Array.prototype.forEach()

بديل for forlolo هو Array.prototype.forEach() ، والذي يستخدم بناء الجملة التالي:

myArray.forEach(function(value, key, myArray) {
    console.log(value);
});

Array.prototype.forEach() معتمد من قبل جميع المتصفحات الحديثة ، وكذلك Internet Explorer 9 والإصدارات الأحدث.

المكتبات

وأخيرًا ، فإن العديد من مكتبات المرافق لديها أيضًا تنوعها الخاص. AFAIK ، الثلاثة الأكثر شعبية هي:

jQuery.each() ، في jQuery :

$.each(myArray, function(key, value) {
    console.log(value);
});

_.each() ، في Underscore.js :

_.each(myArray, function(value, key, myArray) {
    console.log(value);
});

_.forEach() ، في Lodash.js :

_.forEach(myArray, function(value, key) {
    console.log(value);
});




php arrays pdo prepared-statement where-in