2011-09-29 11 views
18

एक पीडीओ कथन लिखते समय, क्या एक चर के मान को दोहराना संभव है? मेरा मतलब है:php pdo दोहराव चर तैयार

$query = "UPDATE users SET firstname = :name WHERE firstname = :name"; 
$stmt = $dbh -> prepare($query); 
$stmt -> execute(array(":name" => "Jackie")); 

कृपया ध्यान दें कि मैं फिर कहता हूँ ": नाम" nameholder जबकि मैं केवल एक बार मूल्य प्रदान करते हैं। मै इसे काम मे कैसे ले सकता हूँ?

उत्तर

19

सरल उत्तर है: आप नहीं कर सकते। पीडीओ तैयार बयानों के लिए एक अमूर्तता का उपयोग करता है जिसमें कुछ सीमाएं होती हैं। दुर्भाग्य से यह एक आप काम के आसपास के लिए कुछ का उपयोग कर की तरह

$query = "UPDATE users SET firstname = :name1 WHERE firstname = :name2"; 
$stmt = $dbh -> prepare($query); 
$stmt -> execute(array(":name1" => "Jackie", ":name2" => "Jackie")); 

ऐसे पीडीओ/MySQL चालक के कुछ संस्करणों के साथ नकल करते तैयार बयान के रूप में, बार-बार नाम वाले पैरामीटर का समर्थन कर रहे कुछ मामलों में, है है; हालांकि, इस पर भरोसा नहीं किया जाना चाहिए, क्योंकि यह भंगुर है (उदाहरण के लिए इसे उन्नयन के लिए अधिक काम की आवश्यकता हो सकती है)।

आप एक नामित पैरामीटर के कई दिखावे का समर्थन करना चाहते हैं, तो आप हमेशा extend PDO and PDOStatement (शास्त्रीय विरासत से या रचना) के द्वारा, या बस PDOStatement और PDO::ATTR_STATEMENT_CLASS विशेषता सेट करके बयान वर्ग के रूप में अपनी कक्षा सेट कर सकते हैं। विस्तारित पीडीओएसटेमेंट (या PDO::prepare) नामित पैरामीटर निकाल सकता है, दोहराने के लिए देख सकता है और स्वचालित रूप से प्रतिस्थापन उत्पन्न कर सकता है। यह इन डुप्लिकेट को भी रिकॉर्ड करेगा। बाध्य और निष्पादन विधियों, जब एक नामित पैरामीटर पारित किया गया है, यह जांच करेगा कि पैरामीटर दोहराया गया है और प्रत्येक प्रतिस्थापन पैरामीटर के मान को बाध्य करता है।

नोट: निम्न उदाहरण अनचाहे है और संभावित में बग हैं (कुछ कथन पार्सिंग से संबंधित कोड टिप्पणियों में उल्लिखित हैं)।

class PDO_multiNamed extends PDO { 
    function prepare($stmt) { 
     $params = array_count_values($this->_extractNamedParams()); 
     # get just named parameters that are repeated 
     $repeated = array_filter($params, function ($count) { return $count > 1; }); 
     # start suffixes at 0 
     $suffixes = array_map(function ($x) {return 0;}, $repeated); 
     /* Replace repeated named parameters. Doesn't properly parse statement, 
     * so may replacement portions of the string that it shouldn't. Proper 
     * implementation left as an exercise for the reader. 
     * 
     * $param only contains identifier characters, so no need to escape it 
     */ 
     $stmt = preg_replace_callback(
      '/(?:' . implode('|', array_keys($repeated)) . ')(?=\W)/', 
      function ($matches) use (&$suffixes) { 
       return $matches[0] . '_' . $suffixes[$matches[0]]++; 
      }, $stmt); 
     $this->prepare($stmt, 
         array(
          PDO::ATTR_STATEMENT_CLASS => array('PDOStatement_multiNamed', array($repeated))) 
      ); 
    } 

    protected function _extractNamedParams() { 
     /* Not actually sufficient to parse named parameters, but it's a start. 
     * Proper implementation left as an exercise. 
     */ 
     preg_match_all('/:\w+/', $stmt, $params); 
     return $params[0]; 
    } 
} 

class PDOStatement_multiNamed extends PDOStatement { 
    protected $_namedRepeats; 

    function __construct($repeated) { 
     # PDOStatement::__construct doesn't like to be called. 
     //parent::__construct(); 
     $this->_namedRepeats = $repeated; 
    } 

    /* 0 may not be an appropriate default for $length, but an examination of 
    * ext/pdo/pdo_stmt.c suggests it should work. Alternatively, leave off the 
    * last two arguments and rely on PHP's implicit variadic function feature. 
    */ 
    function bindParam($param, &$var, $data_type=PDO::PARAM_STR, $length=0, $driver_options=array()) { 
     return $this->_bind(__FUNCTION__, $param, func_get_args()); 
    } 

    function bindValue($param, $var, $data_type=PDO::PARAM_STR) { 
     return $this->_bind(__FUNCTION__, $param, func_get_args()); 
    } 

    function execute($input_parameters=NULL) { 
     if ($input_parameters) { 
      $params = array(); 
      # could be replaced by array_map_concat, if it existed 
      foreach ($input_parameters as $name => $val) { 
       if (isset($this->_namedRepeats[$param])) { 
        for ($i=0; $i < $this->_namedRepeats[$param], ++$i) { 
         $params["{$name}_{$i}"] = $val; 
        } 
       } else { 
        $params[$name] = $val; 
       } 
      } 
      return parent::execute($params); 
     } else { 
      return parent::execute(); 
     } 
    } 

    protected function _bind($method, $param, $args) { 
     if (isset($this->_namedRepeats[$param])) { 
      $result = TRUE; 
      for ($i=0; $i < $this->_namedRepeats[$param], ++$i) { 
       $args[0] = "{$param}_{$i}"; 
       # should this return early if the call fails? 
       $result &= call_user_func_array("parent::$method", $args); 
      } 
      return $result; 
     } else { 
      return call_user_func_array("parent::$method", $args); 
     } 
    } 
} 
+0

मैं कभी नहीं किया है:

function prepareMsSqlQueryParams($query, $params): array { $paramsCount = []; $newParams = []; $pattern = '/(:' . implode('|:', array_keys($params)) . ')/'; $query = preg_replace_callback($pattern, function ($matches) use ($params, &$newParams, &$paramsCount) { $key = ltrim($matches[0], ':'); if (isset($paramsCount[$key])) { $paramsCount[$key]++; $newParams[$key . $paramsCount[$key]] = $params[$key]; return $matches[0] . $paramsCount[$key]; } else { $newParams[$key] = $params[$key]; $paramsCount[$key] = 0; return $matches[0]; } }, $query); return [$query, $newParams]; } 

तो फिर तुम इसे इस तरह उपयोग कर सकते हैं 'ऑन डिप्लिकेट कुंजी अपडेट' कथन में एक ही सूची को दोहराने में कोई समस्या थी ... – jeroen

+1

वास्तव में यह पीडीओ चालक पर थोड़ा सा निर्भर करता है, आपको इसे काम करने पर भरोसा नहीं करना चाहिए। – johannes

+0

दिलचस्प, यह हमेशा मेरे लिए काम करता है। क्या आप उस विषय पर किसी दस्तावेज़ के बारे में जानते हैं? – jeroen

0

मेरे मामले में यह त्रुटि तब दिखाई दी जब मैंने dblib freedts से sqlsrv PDO ड्राइवर में स्विच किया। Dblib ड्राइवर ने त्रुटियों वाले डुप्लिकेट पैरामीटर नामों को संभाला। मैं और यूनियनों के बहुत सारे डुप्लिकेट किए गए पैरामीटर का एक बहुत साथ काफी जटिल गतिशील प्रश्न हैं तो मैं एक समाधान के रूप सहायक निम्नलिखित प्रयोग किया है:

$query = "UPDATE users SET firstname = :name WHERE firstname = :name"; 
$params = [":name" => "Jackie"]; 
// It will return "UPDATE users SET firstname = :name WHERE firstname = :name1"; with appropriate parameters array 
list($query, $params) = prepareMsSqlQueryParams($query, $params); 
$stmt = $dbh->prepare($query); 
$stmt->execute(params); 
संबंधित मुद्दे