Ir al contenido principal

Lección 1 · Autoevaluación

Cómo se usa

Esta página cubre todo lo de la lección 1: qué es PHP, cómo se ejecuta, variables y tipos, operadores, estructuras de control, superglobales, inclusión de archivos y las reglas de seguridad que aparecen desde el primer ejemplo.

Hay 24 preguntas de opción múltiple y 10 ejercicios. En las preguntas, la corrección es inmediata: al elegir una opción se marca en verde la correcta y aparece la explicación de por qué. El error se corrige en el momento, que es cuando todavía se tiene fresco el razonamiento que llevó a elegirlo.

Los ejercicios son de escritura: se resuelven en un archivo, se ejecutan y, si se quiere comparar, la solución está escondida detrás del botón. Una respuesta que se lee y se entiende pero no se probó no cuenta como resuelta.

Preguntas

Agrupadas por tema, en el orden en que se dieron en la lección. Una sola opción es correcta en cada una.

Todavía sin contestar · 24 preguntas

El lenguaje y la ejecución

1. ¿Dónde se ejecuta PHP?

Elegí una opción para verla

En el servidor. El navegador pide una dirección, el servidor ejecuta el código y devuelve el resultado —casi siempre HTML—. El usuario recibe solo el resultado, nunca el programa.

La prueba está al alcance: «ver código fuente» en el navegador no muestra ninguna línea de PHP.

2. Al abrir una página en el navegador se ve el código, con las etiquetas <?php a la vista. ¿Cuál es el diagnóstico?

Elegí una opción para verla

Que el archivo no se está ejecutando. No es un error de sintaxis. Las causas habituales son tres: se abrió como archivo local —la dirección empieza con file:///—, el archivo está fuera de la carpeta del sitio, o el servidor está apagado.

Se arregla pidiéndolo por http://localhost/… con Apache y PHP encendidos.

3. ¿Qué diferencia hay entre php archivo.php y abrir ese mismo archivo desde el navegador?

Elegí una opción para verla

Las dos formas ejecutan el mismo código, pero cambia el entorno:

  • En la terminal el resultado sale por la consola, no hay navegador ni HTML, y no existen las superglobales propias de la web.
  • Desde el navegador el resultado es una respuesta HTTP: hay cabeceras, hay petición, y el navegador interpreta el HTML que recibe.

4. ¿Por qué en un archivo que contiene solo PHP se omite la etiqueta de cierre ?>?

Elegí una opción para verla

Cualquier carácter después de ?> —un espacio, una línea en blanco, el salto de línea final del editor— se envía al navegador como salida. Si ese archivo se incluye en otro que después quiere mandar una cabecera, el error es «headers already sent», y encontrar el espacio culpable puede llevar horas.

Sin etiqueta de cierre, el problema no existe.

Variables, tipos y texto

5. ¿Cuál es la diferencia entre 'Producto: $nombre' y "Producto: $nombre"?

Elegí una opción para verla

echo 'Producto: $nombre';   // Producto: $nombre
echo "Producto: $nombre";   // Producto: Yerba mate 1 kg

Los escapes como \n también funcionan solo en las dobles.

6. ¿Para qué sirven las llaves en "Código {$codigo}A"?

Elegí una opción para verla

Para delimitar el nombre de la variable. Sin las llaves, PHP busca una variable llamada $codigoA, que no existe.

Hacen falta siempre que después del nombre venga un carácter que pueda confundirse con parte de él: una letra, un número o un guion bajo.

7. ¿Qué devuelve empty("0")?

Elegí una opción para verla

Verdadero. El texto «0» está en la lista de valores vacíos, junto con 0, "", [], null y false.

Es un problema cuando el cero es un valor válido —un producto de obsequio con precio 0—: la validación lo rechaza como si el campo estuviera en blanco. En ese caso se compara con === ''.

8. Un producto tiene la clave precio y su valor es null. ¿Qué devuelve cada comprobación?

Elegí una opción para verla

isset es falso cuando el valor es null; array_key_exists es verdadero porque lo que pregunta es si la clave está.

En el catálogo la diferencia es real: con isset parecería que el dato no existe, cuando en realidad el producto está incompleto.

9. ¿Por qué 0.1 + 0.2 == 0.3 da falso?

Elegí una opción para verla

var_dump(0.1 + 0.2);        // float(0.30000000000000004)
var_dump(0.1 + 0.2 == 0.3); // bool(false)

Se compara con una tolerancia: abs($a - $b) < 0.00001. Con dinero, además, no se redondea en el medio del cálculo: se redondea al final.

10. ¿Qué hace declare(strict_types=1)?

Elegí una opción para verla

Desactiva las conversiones automáticas. Va como primera instrucción del archivo, antes de cualquier otra cosa, y afecta a las llamadas que se hacen desde ese archivo.

Con eso, un precio que llega como texto en lugar de número avisa ahí mismo y no tres pantallas después.

Operadores y comparaciones

11. ¿Qué diferencia hay entre == y ===?

Elegí una opción para verla

Se usa === siempre, salvo motivo concreto. La conversión automática de == produce resultados que sorprenden: 10 == "10" es verdadero, y en un control de acceso esa diferencia es la que deja pasar a quien no corresponde.

12. Con $a = 1850 y $b = 1200, ¿qué imprime echo 'Total: ' . $a + $b;?

Elegí una opción para verla

Imprime 3050. La concatenación tiene menos precedencia que la suma, así que primero se resuelve $a + $b y después se concatena con el texto. Como el texto no es numérico, el resultado termina siendo el número.

Para el total con texto hay que usar paréntesis: 'Total: ' . ($a + $b).

13. ¿Por qué $a = true and false deja $a en true y $a = true && false lo deja en false?

Elegí una opción para verla

$a = true and false;   // $a vale true: primero se asigna
$b = true && false;    // $b vale false

Por eso se usan siempre && y ||.

14. ¿Qué dan '2' + '3' y '2' . '3'?

Elegí una opción para verla

+ suma y . concatena. Es el error típico al armar un código a partir de partes: se quiere unir y se termina sumando, o al revés.

15. ¿Qué devuelve el operador <=>?

Elegí una opción para verla

Devuelve -1, 0 o 1: negativo si el izquierdo es menor, cero si son iguales, positivo si es mayor.

Es exactamente lo que espera usort(). Para textos conviene strcmp(), porque el operador depende de la configuración regional.

Estructuras de control

16. En una cadena if / elseif / else con dos condiciones verdaderas, ¿qué pasa?

Elegí una opción para verla

La primera cuya condición sea verdadera, y después se sale. Las demás no se evalúan aunque también lo sean.

Por eso el orden importa: si se pregunta primero $stock > 0, nunca se llega a la rama de $stock > 10.

17. ¿Qué ventaja tiene match sobre switch?

Elegí una opción para verla

match compara con ===, devuelve un valor y, si ningún caso coincide y no hay default, lanza un error en lugar de seguir de largo.

Consecuencia práctica: si el dato llega como texto —de un formulario, siempre— hay que convertirlo antes, porque 2 y "2" no son iguales con ===.

18. ¿Cuándo conviene for y cuándo foreach?

Elegí una opción para verla

  • for: cantidad conocida (tres cuotas, diez productos).
  • while: depende de una condición que cambia adentro.
  • foreach: recorrer un array completo. Es el más usado.

do…while se usa cuando el bloque tiene que ejecutarse al menos una vez.

19. Después de recorrer un array con as &$valor, ¿qué conviene hacer?

Elegí una opción para verla

La variable del foreach queda apuntando al último elemento. Si después se recorre el mismo array con otro foreach normal, la última vuelta pisa ese elemento con el valor anterior.

Se evita liberando la variable con unset($valor) al terminar.

Entrada, salida, seguridad e inclusión

20. ¿Qué son las superglobales?

Elegí una opción para verla

Arrays que PHP crea y que están disponibles en cualquier parte, sin declararlos ni pasarlos como parámetro.

Las de todos los días: $_GET, $_POST, $_SESSION, $_FILES y $_SERVER.

21. ¿Para qué se usa htmlspecialchars() al mostrar un dato que llegó por la dirección?

Elegí una opción para verla

Para que el navegador muestre el texto en lugar de interpretarlo. Si no se escapa, un enlace armado con HTML o JavaScript se ejecuta en el navegador de quien lo abre: es el ataque XSS.

Y se escapa al mostrar, no al guardar: escapar al guardar ensucia la base con entidades y rompe cualquier otro uso del dato.

22. ¿Por qué se usa $_SERVER['SCRIPT_NAME'] y no $_SERVER['PHP_SELF'] en el action de un formulario?

Elegí una opción para verla

Si alguien pide /productos.php/<script>…, eso aparece en PHP_SELF. Usarlo sin escapar en el action es un XSS servido en bandeja.

SCRIPT_NAME devuelve solo la ruta del archivo.

23. ¿Cuál es la diferencia entre require e include?

Elegí una opción para verla

require para lo que el programa necesita —configuración, conexión, una clase—; include para lo opcional.

El sufijo _once evita incluir dos veces, y se usa siempre que el archivo defina funciones o clases: declararlas dos veces es error fatal.

24. ¿Qué resuelve armar la ruta con __DIR__ en require __DIR__ . '/encabezado.php'?

Elegí una opción para verla

__DIR__ es la carpeta del archivo actual, así que la inclusión funciona sin importar desde dónde se ejecute el programa.

Con una ruta relativa como 'encabezado.php', el resultado depende del directorio de trabajo y cambia según cómo se llame al script.

Ejercicios de práctica

Diez ejercicios, en orden de dificultad. Los tres primeros son de lenguaje puro; del cuarto al séptimo combinan estructuras de control y datos; los últimos ya tienen entrada, archivos y salida HTML.

Ejercicio 1

Escribir un programa que muestre el nombre de la tienda, la fecha de hoy y el precio de un producto con el IVA incluido. Los datos van en variables; el IVA, en una constante.

<?php

declare(strict_types=1);

const IVA = 0.21;

$tienda = 'Tienda La Esquina';
$nombre = 'Yerba mate 1 kg';
$precio = 1850.50;

$final = round($precio * (1 + IVA), 2);

echo $tienda . " - " . date('d/m/Y') . "\n";
echo $nombre . ": $" . number_format($final, 2, ',', '.');

Lo que se evalúa: constante en mayúsculas, variables con nombres claros, number_format para el precio y round al final.

Ejercicio 2

Predecir qué imprime cada línea, sin ejecutar: $a = 7; $b = 2; con echo $a / $b;, echo $a % $b;, echo $a . $b; y echo 'R: ' . $a + $b;.

  • $a / $b → 3.5: la división no redondea.
  • $a % $b → 1: el resto.
  • $a . $b → 72: concatena.
  • 'R: ' . $a + $b → 9: la suma se resuelve antes que la concatenación.

Ejercicio 3

Dado un código de producto que llega por la dirección, mostrar «Producto 1042» solo si el valor es realmente un número. Si no vino o no es numérico, mostrar un mensaje de error.

<?php

declare(strict_types=1);

$codigo = $_GET['codigo'] ?? '';

if ($codigo === '' || !ctype_digit($codigo)) {
    echo 'Código inválido';
} else {
    echo 'Producto ' . htmlspecialchars($codigo, ENT_QUOTES, 'UTF-8');
}

Dos detalles: ?? evita el aviso de clave inexistente, y ctype_digit rechaza "1042 OR 1=1", que es texto válido para PHP.

Ejercicio 4

Escribir una tabla HTML con las tres etapas del ciclo lectivo y, en cada fila, el nombre de la etapa y si está cerrada o abierta. Usar match.

<?php
$etapas = [1, 2, 3];
?>
<table class="table">
    <tbody>
        <?php foreach ($etapas as $etapa): ?>
            <tr>
                <td>Etapa <?= $etapa ?></td>
                <td><?= match ($etapa) {
                    1 => 'Cerrada',
                    2 => 'Abierta',
                    3 => 'Pendiente',
                    default => '—',
                } ?></td>
            </tr>
        <?php endforeach; ?>
    </tbody>
</table>

match devuelve un valor, así que se puede usar directamente dentro de la etiqueta de salida.

Ejercicio 5

Mostrar los números del 1 al 20, salteando los múltiplos de 3 y cortando el recorrido al llegar a 17.

for ($i = 1; $i <= 20; $i++) {
    if ($i % 3 === 0) {
        continue;
    }

    if ($i > 17) {
        break;
    }

    echo $i . "\n";
}

El orden de las dos comprobaciones importa: continue salta la vuelta, break corta el bucle entero.

Ejercicio 6

Recorrer un carrito de cuatro productos y mostrar el total. Uno de los productos puede tener precio null, y en ese caso no se suma.

$carrito = [
    'Yerba mate' => 1850.50,
    'Azúcar'    => 1200,
    'Fideos'    => null,
    'Arroz'     => 1350,
];

$total = 0.0;

foreach ($carrito as $producto => $precio) {
    if ($precio === null) {
        continue;
    }

    $total += $precio;
}

echo 'Total: ' . number_format($total, 2, ',', '.');

El null se compara con ===: con == se confundiría con 0, y un producto sin precio no es un producto gratis.

Ejercicio 7

Corregir este código, que tiene cuatro errores, y explicar cada uno: $precio = $_POST[precio] seguido de if ($precio = 0) { echo "gratis"; }.

<?php

declare(strict_types=1);

$precio = $_POST['precio'] ?? '';

if ($precio === '' || !is_numeric($precio)) {
    echo 'Precio inválido';
} elseif ((float) $precio === 0.0) {
    echo 'Gratis';
}
  • Faltaba el punto y coma.
  • $_POST[precio] va con comillas: sin ellas precio se interpreta como constante y falla.
  • = asigna, no compara: hay que usar ===.
  • Falta comprobar que el dato llegó y que es numérico antes de usarlo.

Ejercicio 8

Armar dos archivos: encabezado.php, que recibe un $titulo y abre el documento, y catalogo.php, que lo incluye, muestra un listado y cierra el HTML.

<?php
// encabezado.php
?>
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="utf-8">
    <title><?= htmlspecialchars($titulo, ENT_QUOTES, 'UTF-8') ?></title>
</head>
<body>
<?php
// catalogo.php
$titulo = 'Catálogo';
$productos = ['Yerba mate', 'Azúcar', 'Fideos'];

require __DIR__ . '/encabezado.php';
?>
    <ul>
        <?php foreach ($productos as $producto): ?>
            <li><?= htmlspecialchars($producto, ENT_QUOTES, 'UTF-8') ?></li>
        <?php endforeach; ?>
    </ul>
</body>
</html>

Ejercicio 9

Un formulario envía el nombre de un producto por POST. Mostrarlo en pantalla evitando XSS y, además, con la primera letra de cada palabra en mayúscula.

<?php

declare(strict_types=1);

$nombre = trim($_POST['nombre'] ?? '');

if ($nombre === '') {
    echo 'Falta el nombre del producto';
} else {
    $nombre = mb_convert_case($nombre, MB_CASE_TITLE, 'UTF-8');

    echo 'Producto: ' . htmlspecialchars($nombre, ENT_QUOTES, 'UTF-8');
}

Se normaliza con mb_* porque ucfirst trabaja con bytes y rompe los acentos. Y se escapa después de formatear, no antes.

Ejercicio 10

Explicar qué pasa al ejecutar include 'piedepagina.php'; cuando el archivo no existe, y en qué cambiaría con require y con require_once.

  • include: PHP emite un warning y el programa sigue. En una página con datos sensibles, sigue mostrando la mitad de la información.
  • require: emite un error fatal y detiene la ejecución. Es lo que corresponde cuando sin ese archivo el programa no tiene sentido.
  • require_once: igual, pero si el archivo ya se incluyó no lo vuelve a incluir. Necesario cuando define funciones o clases.

Cómo saber si está bien

Si fallaste… Volvé a
Las preguntas 1 a 4Qué es PHP, El caso que vamos a seguir y Cómo se ejecuta.
Las preguntas 5 a 10Variables y Tipos de datos, con atención a isset, empty y a la interpolación.
Las preguntas 11 a 15Operadores, sobre todo la tabla de comparaciones y la precedencia.
Las preguntas 16 a 19Estructuras de control.
Las preguntas 20 a 24Entrada y salida, Las superglobales e Incluir archivos.
Los ejercicios 7 a 10Errores frecuentes: son los que juntan todas las trampas en un solo lugar.

Si acertaste 18 o más, la lección está firme. Entre 12 y 17 conviene releer los temas de las que fallaron antes de seguir. Con menos de 12, la lección 2 va a costar: casi todo lo que viene se apoya en estas ideas.

Lo que hay que poder explicar

Al terminar, sin mirar el material, tendrías que poder explicar cada una de estas frases en dos o tres oraciones:

Idea La respuesta en una línea
PHP se ejecuta en el servidorEl navegador recibe solo el resultado; cada petición empieza de cero.
Comillas simples y doblesLas dobles interpolan; las simples muestran el texto literal.
=== siempre== convierte tipos, y esa conversión produce errores lógicos y fallas de seguridad.
Las superglobales no son confiablesLlegan como texto sin validar: comprobar que existan, validar el formato, escapar al mostrar.
Todo dato de afuera se escapahtmlspecialchars() al mostrar, nunca al guardar.
require_once con __DIR__Lo indispensable frena si falta, y la ruta no depende del directorio de trabajo.

La lección 2 toma todo esto como punto de partida y agrega funciones, arrays y texto.

Licencia. El material de esta página es elaboración propia de Prof Mauro Bobyk —a partir de las fuentes que detalla el pie del sitio— y se publica bajo una licencia Creative Commons BY-NC-SA 4.0.