0

我对 Mysqli 完全陌生(从 MySQL 切换),所以为了保持简单、安全和可靠,通过这个万能的函数绝对运行所有 Mysqli 查询是否有意义?

为什么或为什么不呢?两种方式的利弊是什么?

function mysqli_prepared_query($link,$sql,$typeDef = FALSE,$params = FALSE){ 
  if($stmt = mysqli_prepare($link,$sql)){ 
    if(count($params) == count($params,1)){ 
      $params = array($params); 
      $multiQuery = FALSE; 
    } else { 
      $multiQuery = TRUE; 
    }  

    if($typeDef){ 
      $bindParams = array();    
      $bindParamsReferences = array(); 
      $bindParams = array_pad($bindParams,(count($params,1)-count($params))/count($params),"");         
      foreach($bindParams as $key => $value){ 
        $bindParamsReferences[$key] = &$bindParams[$key];  
      } 
      array_unshift($bindParamsReferences,$typeDef); 
      $bindParamsMethod = new ReflectionMethod('mysqli_stmt', 'bind_param'); 
      $bindParamsMethod->invokeArgs($stmt,$bindParamsReferences); 
    } 

    $result = array(); 
    foreach($params as $queryKey => $query){ 
      foreach($bindParams as $paramKey => $value){ 
        $bindParams[$paramKey] = $query[$paramKey]; 
      } 
      $queryResult = array(); 
      if(mysqli_stmt_execute($stmt)){ 
        $resultMetaData = mysqli_stmt_result_metadata($stmt); 
        if($resultMetaData){                                                                               
          $stmtRow = array();   
          $rowReferences = array(); 
          while ($field = mysqli_fetch_field($resultMetaData)) { 
            $rowReferences[] = &$stmtRow[$field->name]; 
          }                                
          mysqli_free_result($resultMetaData); 
          $bindResultMethod = new ReflectionMethod('mysqli_stmt', 'bind_result'); 
          $bindResultMethod->invokeArgs($stmt, $rowReferences); 
          while(mysqli_stmt_fetch($stmt)){ 
            $row = array(); 
            foreach($stmtRow as $key => $value){ 
              $row[$key] = $value;           
            } 
            $queryResult[] = $row; 
          } 
          mysqli_stmt_free_result($stmt); 
        } else { 
          $queryResult[] = mysqli_stmt_affected_rows($stmt); 
        } 
      } else { 
        $queryResult[] = FALSE; 
      } 
      $result[$queryKey] = $queryResult; 
    } 
    mysqli_stmt_close($stmt);   
  } else { 
    $result = FALSE; 
  } 

  if($multiQuery){ 
    return $result; 
  } else { 
    return $result[0]; 
  } 
} 
?> 

Example(s): 
For a table of firstName and lastName: 
John Smith 
Mark Smith 
Jack Johnson 
Bob Johnson 

<?php 
//single query, single result 
$query = "SELECT * FROM names WHERE firstName=? AND lastName=?"; 
$params = array("Bob","Johnson"); 

mysqli_prepared_query($link,$query,"ss",$params) 
/* 
returns array( 
0=> array('firstName' => 'Bob', 'lastName' => 'Johnson') 
) 
*/ 

//single query, multiple results 
$query = "SELECT * FROM names WHERE lastName=?"; 
$params = array("Smith"); 

mysqli_prepared_query($link,$query,"s",$params) 
/* 
returns array( 
0=> array('firstName' => 'John', 'lastName' => 'Smith') 
1=> array('firstName' => 'Mark', 'lastName' => 'Smith') 
) 
*/ 

//multiple query, multiple results 
$query = "SELECT * FROM names WHERE lastName=?"; 
$params = array(array("Smith"),array("Johnson")); 

mysqli_prepared_query($link,$query,"s",$params) 
/* 
returns array( 
0=> 
array( 
0=> array('firstName' => 'John', 'lastName' => 'Smith') 
1=> array('firstName' => 'Mark', 'lastName' => 'Smith') 
) 
1=> 
array( 
0=> array('firstName' => 'Jack', 'lastName' => 'Johnson') 
1=> array('firstName' => 'Bob', 'lastName' => 'Johnson') 
) 
) 
*/ 
4

3 回答 3

9

I'm sorry, but no I think it's a terrible idea.

A good function/method should be short, to the point, and designed to do one thing and only one thing well. It should also try to avoid branching logic where possible (keep the number of if and switch statements to a minimum). Such functions are easy to understand as their inner workings can be grasped with relatively little effort.

The longer a function is, the harder it becomes to understand because the programmer has to hold more in their head regarding how it works. The more if/switch/try/catch/throw statements the function contains, the harder it becomes to understand because they modify how execution might flow through the function. You have to take into account something known as the npath complexity (a count of the possible ways a function can execute). Every if you add will double the npath complexity. Based purely on counting ifs I got a complexity of 64, which is far too high! Loops can increase npath complexity as well, so the actual complexity metric for your function is probably a lot higher than that.

Changing a function like the one you've given becomes far more work than it would be if it was a collection of smaller simple functions, because it's very difficult to make a particular change to achieve the intended new behaviour without having unwanted knock-on effects. Of course you can use a unit test to make sure that this doesn't happen, but with a high npath complexity, the number of tests you'll have to write to make sure the functionality of your function is fully covered is inordinately large.

Good general rules of thumb:

  • If a function's body can't fit on your screen, then it probably can't fit in your head either. Avoid functions that are longer than your editor window. You should never have to scroll to see the entirety of a function.
  • You get 2 ifs per function. More than that and the npath complexity can start to become unmanageable.
  • A function should do one thing well. A function that tries to be a jack of all trades will probably fail to be correct in every case. Additionally, the more responsibility a function tries to take on the more difficult it becomes for the function to meet all the responsibilities it has.
  • Small functions are reusable, big ones aren't.
  • In the name of everything that's holy, comment your code! It's almost impossible for someone else to look at your function and figure out what it's meant to do. Breaking it down and following the earlier guidelines would help considerably, but even then computer code isn't as good as expressing ideas to other human beings than plain English is. Comments clarify points that might not be clear at a casual glance and can help another programmer figure out what was in your head when you were designing and implementing the code. They cost nothing in terms of execution time so there really is no excuse not to comment. If you leave this code alone and come back to look at it again in a year's time, I can guarantee that you'll never figure out what you were thinking at the time you wrote it.

A much better solution would be to implement a class that provides the services you need as a series of methods.

An even better solution would be to check how much of this PHP can do through its built in functionality for you. As I can't really understand your function I couldn't say for sure whether PHP can already do what you need this function to do, but my suspicion is that a good chunk of it is already implemented in PHP.

于 2012-05-17T12:02:08.323 回答
4

为什么要重新发明轮子?MySQLi 已经有一个类可以使用。

http://us2.php.net/manual/en/class.mysqli.php

从此链接开始并开始正确使用它。

于 2012-05-17T11:52:27.203 回答
1

一刀切不可避免地意味着会有一些(可能很多)代码只针对一种特定情况,并不适用于每个操作。函数中将有一些代码会妨碍您。可能还会有很多代码没有考虑到的边缘情况,当你发现它们时,它会让你在调试代码时感到头疼。

对此的简单回答是“不要使用它”。它的效率会降低,并且可能会使您的代码对其他开发人员感到困惑。

学习正确使用 MySQLi。这并不难,从长远来看,它会给你带来很大的优势。

于 2012-05-17T11:50:10.437 回答