php - tiempos - Referencia: preguntas frecuentes sobre DOP
problemas resueltos de estudio del trabajo (3)
¿Que es esto?
Esta es una lista de preguntas frecuentes sobre objetos de datos PHP
¿Por qué es esto?
Como PDO tiene algunas características desconocidas para un usuario regular de PHP, las preguntas sobre las declaraciones preparadas y el manejo de errores en PDO son bastante frecuentes. Entonces, este es solo un lugar donde se pueden encontrar todos.
¿Qué debería hacer aquí?
Si su pregunta ha sido enviada de cerca con esta lista, encuentre su pregunta a continuación y aplique la solución a su código. También es una buena idea echar un vistazo breve a otras preguntas, para estar preparado para otras trampas comunes.
La lista
- La consulta PDO falla pero no puedo ver ningún error. ¿Cómo obtener un mensaje de error de PDO?
- ¿Cómo puedo usar declaraciones preparadas con el operador LIKE?
- ¿Cómo puedo crear una declaración preparada para el operador IN ()?
- ¿Puedo usar una declaración preparada PDO para vincular un identificador (una tabla o nombre de campo) o una palabra clave de sintaxis?
- La declaración preparada de PDO provoca un error en la instrucción LIMIT
Ver también
- Referencia - ¿Qué significa este símbolo en PHP?
- Referencia - ¿Qué significa este error en PHP?
- Referencia: ¿qué es el alcance variable, qué variables son accesibles desde dónde y qué son los errores de "variable indefinida"?
¿Cómo puedo usar declaraciones preparadas con el operador LIKE?
La declaración preparada puede representar literal de datos completos solamente . No es una parte de literal, ni una expresión compleja, ni un identificador. Pero solo cadena o número . Entonces, un error muy común es una consulta como esta:
$sql = "SELECT * FROM t WHERE column LIKE ''%?%''";
Si reflexiona un poco sobre esta consulta, comprenderá que al estar dentro de las comillas simples, un signo de interrogación se convierte en un signo de interrogación literal, sin ningún significado especial para las declaraciones preparadas.
Entonces, uno tiene que enviar un literal de cadena completo usando una declaración preparada. Hay 2 formas posibles:
o bien prepare la expresión COMPLETA primero:
$name = "%$name%"; $stm = $pdo->prepare("SELECT * FROM table WHERE name LIKE ?"); $stm->execute(array($name)); $data = $stm->fetchAll();
o usa una concatenación dentro de la consulta
$sql = "SELECT * FROM t WHERE column LIKE concat(''%'',?,''%'')";
aunque el último parece demasiado hinchado.
La consulta PDO falla pero no puedo ver ningún error. ¿Cómo obtener un mensaje de error de PDO?
Para poder ver los errores de la base de datos, uno debe configurar el PDO errmode a las excepciones. Las excepciones son mejores que los errores normales de muchas maneras: siempre contienen un seguimiento de la pila, se pueden capturar usando try..catch o manejarse con un manejador de error dedicado. E incluso no controlados, actúan como errores regulares de PHP y proporcionan toda la información importante, siguiendo la configuración de informes de errores en todo el sitio.
Tenga en cuenta que establecer este modo como una opción de conexión permitirá a PDO lanzar excepciones sobre errores de conexión también, lo cual es muy importante.
Entonces, aquí hay un ejemplo para crear una conexión PDO de la manera correcta:
$dsn = "mysql:host=$host;dbname=$db;charset=utf8";
$opt = array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
// other options
);
$pdo = new PDO($dsn, $user, $pass, $opt);
Al conectarse de esta manera, siempre se le notificarán todos los errores de la base de datos, ocurridos durante la ejecución de la consulta. Tenga en cuenta que debe poder ver los errores de PHP en general. En un sitio en vivo, tiene que echar un vistazo a los registros de errores, por lo tanto, la configuración debe ser
error_reporting(E_ALL);
ini_set(''display_errors'',0);
ini_set(''log_errors'',1);
mientras que en un servidor de desarrollo local está bien hacer errores en la pantalla:
error_reporting(E_ALL);
ini_set(''display_errors'',1);
y, por supuesto, nunca debe usar el operador de supresión de errores ( @
) delante de sus declaraciones de PDO.
Además, debido a muchos malos ejemplos que te dicen que envuelvas cada declaración PDO en el bloque try..catch
, tengo que hacer una nota distinta:
NO use el operador try..catch solo para repetir un mensaje de error. La excepción no detectada ya es excelente para este propósito, ya que actuará de la misma manera que otros errores de PHP, por lo que puede definir el comportamiento utilizando la configuración de todo el sitio, por lo que recibirá su mensaje de error sin este código inútil. Si bien el mensaje de error con ecos incondicionales puede revelar información sensible a un posible atacante, puede confundir a un visitante honesto.
- Se podría agregar un controlador de excepción personalizado más tarde, pero no es obligatorio. Especialmente para usuarios nuevos, se recomienda utilizar excepciones no controladas, ya que son extremadamente informativas, útiles y seguras.
- Use
try..catch
solo si va a manejar el error en sí, es decir, para deshacer una transacción.
La declaración preparada de PDO causa un error en la cláusula LIMIT
Para fines de compatibilidad, PDO simplemente emulará las declaraciones preparadas al sustituir los marcadores de posición con datos reales, en lugar de enviarlos al servidor por separado, a menos que se indique lo contrario. Y con el enlace "perezoso" (usando array en execute ()), PDO tratará cada parámetro como una cadena. Como resultado, ¿el LIMIT ?,?
preparado LIMIT ?,?
la consulta se convierte en LIMIT ''10'', ''10''
que es una sintaxis no válida que hace que la consulta falle.
Este problema puede ser resuelto
desactivando el modo de emulación (ya que MySQL puede ordenar correctamente todos los marcadores de posición):
$conn->setAttribute( PDO::ATTR_EMULATE_PREPARES, false );
vinculando y configurando el tipo correcto (PDO :: PARAM_INT) explícitamente:
$stm = $pdo->prepare(''SELECT * FROM table LIMIT ?, ?''); $stm->bindValue(1, $limit_from,PDO::PARAM_INT); $stm->bindValue(2, $per_page,PDO::PARAM_INT); $stm->execute(); $data = $stm->fetchAll();