Ir al contenido principal

Lección 2 · Autoevaluación

Cómo se usa

Esta página cubre todo lo de la lección 2: funciones, parámetros, valores de retorno, ámbito, tipos, arrays, ordenamiento, strings y normalización.

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. Aprender del error en el momento funciona mejor que corregir todo al final, cuando el razonamiento que llevó a elegir ya se olvidó.

Una advertencia útil: casi todas las trampas de esta lección son casos borde —el array vacío, el texto con acento, la posición cero, el resultado que es false—. Si un ejercicio se resuelve con el caso feliz y no se prueba el borde, todavía no está resuelto.

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

Definir, llamar y pasar datos

1. ¿Qué ventaja concreta tiene escribir una función en lugar de repetir la fórmula del IVA en cada pantalla?

Elegí una opción para verla

La regla se escribe una sola vez: el día que cambia la alícuota, se cambia en un lugar y no hay que acordarse de cuatro archivos.

Y una segunda ventaja, menos visible: la función se puede probar sola, sin abrir el navegador ni la base de datos.

2. ¿Se puede llamar a una función antes de la línea donde está declarada?

Elegí una opción para verla

Sí. PHP primero lee todas las declaraciones del archivo y después ejecuta.

Eso no vale para las funciones anónimas asignadas a una variable, ni para las que están en un archivo que todavía no se incluyó.

3. Respecto de mayúsculas y minúsculas en los nombres, ¿qué distingue cada cosa?

Elegí una opción para verla

precioConIva() y precioconiva() son la misma función; $precio y $Precio son dos variables distintas.

Aunque PHP no lo exija, la convención es escribir los nombres siempre igual, porque quien lee no sabe de esta diferencia.

4. ¿Por qué los parámetros con valor por defecto van al final de la lista?

Elegí una opción para verla

Si el opcional no se pasa, el obligatorio que viene después queda sin valor y PHP no sabría qué hacer.

function precioConIva(float $precio, float $tasa = 0.21): float

5. ¿Para qué sirven los argumentos con nombre?

Elegí una opción para verla

precioConIva(tasa: 0.105, precio: 1000);

Son útiles cuando la función tiene varios parámetros opcionales y solo se quiere cambiar uno del medio. Y, sobre todo, hacen que la llamada se lea: quien la mira sabe qué es cada número.

Retorno, ámbito y tipos

6. ¿Qué dos cosas hace return?

Elegí una opción para verla

Devuelve un valor y termina la función. Todo lo que esté después no se ejecuta.

Eso permite escribir las validaciones primero y el trabajo después: son las cláusulas de guarda, que dejan el camino normal sin anidar.

7. Una función sin return devuelve…

Elegí una opción para verla

null. Es peligroso porque la cuenta sigue: null se comporta como cero o como texto vacío según el contexto y el resultado equivocado aparece lejos de la causa.

Se evita declarando el tipo de retorno: con : float, si falta el return, el error aparece en la definición de la función.

8. ¿Qué significa : void en el tipo de retorno?

Elegí una opción para verla

Que no devuelve nada. Se usa en funciones que solo imprimen o que modifican un archivo: function mostrar(string $nombre): void.

9. ¿Qué pasa cuando un array se pasa como argumento a una función y la función lo modifica?

Elegí una opción para verla

$rebajado = aplicarDescuento($catalogo);   // hay que devolverlo

Es una ventaja —quien llama sabe que sus datos no cambian— pero obliga a devolver el resultado. La alternativa es un & delante del parámetro, que modifica el original: se usa poco y conviene evitarlo.

10. ¿Qué diferencia hay entre ?string y mixed?

Elegí una opción para verla

?string es la forma corta de string|null: un texto o nada. mixed es cualquier valor —número, texto, array, objeto o null— y obliga a comprobar el tipo antes de operar.

Arrays

11. Un array tiene la clave 'precio' con valor 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 pregunta si la clave está.

Con isset parecería que el dato no existe, cuando en realidad el producto está incompleto.

12. Después de unset($catalogo[2]) en un array de cinco elementos, ¿qué claves quedan?

Elegí una opción para verla

Quedan las que había, con el hueco. Para renumerar de corrido se usa array_values($catalogo).

Importa cuando después se accede por posición.

13. ¿Qué hace array_filter() con las claves del array que devuelve?

Elegí una opción para verla

Las conserva. Si pasaron el filtro los elementos 0 y 2, el resultado tiene las claves 0 y 2.

Si después se accede por posición, hay que envolver: array_values(array_filter(...)). Es el detalle que más veces se olvida.

14. ¿Cuál es la forma correcta de leer el nombre de un producto dentro de un foreach ($catalogo as $producto)?

Elegí una opción para verla

La clave va entre comillas. Sin comillas, nombre se interpreta como una constante y lanza un error fatal.

Y se lee del producto, no del catálogo: dentro del foreach, $producto es el elemento actual.

15. ¿Qué diferencia hay entre $catalogo[] = $p; y $catalogo[$codigo] = $p;?

Elegí una opción para verla

[] usa la clave numérica siguiente. Con [$codigo] se agrega en esa clave o se reemplaza el valor anterior, sin aviso.

Ordenar y funciones de array

16. ¿Qué devuelve sort($precios)?

Elegí una opción para verla

Devuelve un booleano y ordena el array en el lugar, renumerando las claves. Por eso $ordenado = sort($precios) deja $ordenado en true.

17. Para ordenar un array asociativo por valor sin perder las claves, ¿qué función se usa?

Elegí una opción para verla

  • sort(): por valor, pierde claves.
  • asort(): por valor, conserva claves.
  • ksort(): por clave.

Para un array de arrays no sirve ninguna de las tres: se usa usort().

18. ¿Qué tiene que devolver la función que se le pasa a usort()?

Elegí una opción para verla

Negativo si el primero va antes, cero si dan igual, positivo si va después. Es exactamente lo que devuelve <=>.

usort($catalogo, fn (array $a, array $b): int => $a['precio'] <=> $b['precio']);

19. ¿Por qué conviene strcmp() antes que <=> para ordenar textos?

Elegí una opción para verla

El orden con <=> puede cambiar de una máquina a otra, y además <=> entre textos numéricos compara como números: "10" quedaría antes que "9". strcmp() compara siempre igual.

20. ¿Por qué se pasa true como tercer argumento a in_array()?

Elegí una opción para verla

Sin ese argumento compara con ==, y una comparación floja en un control de permisos significa dar acceso a quien no corresponde. Con true, compara con ===.

Strings y normalización

21. ¿Cuánto devuelve strlen('azúcar')?

Elegí una opción para verla

7: strlen cuenta bytes, y en UTF-8 una letra acentuada ocupa dos. Con mb_strlen('azúcar') devuelve 6.

La misma diferencia afecta a substr, strtoupper y compañía, que pueden partir un carácter al medio o romper el acento.

22. ¿En qué orden van los argumentos de implode()?

Elegí una opción para verla

Primero el separador y después el array: implode(', ', $nombres). Es el orden que se confunde, porque explode va al revés —separador y texto—.

23. ¿Por qué strpos($texto, 'a') se compara con !== false?

Elegí una opción para verla

La posición 0 significa «está al principio», y se evalúa como falso. Solo === false distingue «no está» de «está en la primera posición».

Para no caer en esa trampa están str_contains, str_starts_with y str_ends_with, que responden verdadero o falso.

24. Al buscar con texto normalizado, ¿qué hay que normalizar?

Elegí una opción para verla

Los dos lados. Comparar un texto normalizado con uno sin normalizar no arregla nada: 'azucar' no es igual a 'Azúcar'.

Y normalizar sirve para comparar, no para mostrar: en pantalla va el nombre original, escapado.

Ejercicios de práctica

Diez ejercicios, en orden de dificultad. Los cuatro primeros son de funciones puras; del quinto al octavo combinan arrays y texto; los dos últimos juntan todo.

Ejercicio 1

Escribir precioConIva() que reciba el precio y una tasa opcional del 21 %, devuelva el precio final con dos decimales y devuelva null si el precio no es numérico o es negativo.

function precioConIva(mixed $precio, float $tasa = 0.21): ?float
{
    if (!is_numeric($precio)) {
        return null;
    }

    $valor = (float) $precio;

    if ($valor < 0) {
        return null;
    }

    return round($valor * (1 + $tasa), 2);
}

El tipo ?float obliga a quien llama a contemplar el null. Las dos guardas van antes del cálculo: si el dato no sirve, se sale.

Ejercicio 2

Escribir estadoStock() que reciba el stock y devuelva 'sin stock', 'últimas unidades' (menos de 5) o 'disponible'. Usar cláusulas de guarda, sin anidar.

function estadoStock(int $stock): string
{
    if ($stock <= 0) {
        return 'sin stock';
    }

    if ($stock < 5) {
        return 'últimas unidades';
    }

    return 'disponible';
}

Las guardas van de menor a mayor: primero el caso imposible, después el urgente, y lo que queda es el normal.

Ejercicio 3

Escribir totalCarrito() que reciba una cantidad variable de precios y devuelva el total redondeado. Después llamarla con un array ya armado.

function totalCarrito(float ...$precios): float
{
    return round(array_sum($precios), 2);
}

echo totalCarrito(1850.50, 1200, 990.75);   // 4041.25

$carrito = [1850.50, 1200, 990.75];
echo totalCarrito(...$carrito);              // 4041.25

El ... funciona en los dos sentidos: junta argumentos sueltos en un array, y desparrama un array en argumentos.

Ejercicio 4

Escribir una función que devuelva el resumen de una venta: cantidad de productos, total y total con IVA. Explicar por qué conviene devolver un array con claves.

function resumenVenta(array $carrito): array
{
    $total = array_sum($carrito);

    return [
        'cantidad' => count($carrito),
        'total'    => round($total, 2),
        'conIva'   => round($total * 1.21, 2),
    ];
}

Con claves, quien recibe el resultado no tiene que adivinar qué hay en cada posición. Un array numérico obligaría a recordar que «el segundo es el total», y eso se rompe en cuanto alguien agrega un dato en el medio.

Ejercicio 5

Usando array_map y una función flecha, obtener los precios con un 15 % de descuento, sin modificar el array original.

$descuento = 0.15;

$rebajados = array_map(
    fn (float $precio): float => round($precio * (1 - $descuento), 2),
    $precios
);

La función flecha toma $descuento del ámbito de afuera sin use. Y array_map devuelve un array nuevo: el original queda como estaba.

Ejercicio 6

Filtrar el catálogo para quedarse con los productos con stock y precio menor a 1500, y ordenarlos del más barato al más caro.

$seleccion = array_values(array_filter(
    $catalogo,
    fn (array $p): bool => $p['stock'] > 0 && $p['precio'] < 1500
));

usort($seleccion, fn (array $a, array $b): int => $a['precio'] <=> $b['precio']);

array_values es necesario porque array_filter conserva las claves originales.

Ejercicio 7

Ordenar el catálogo alfabéticamente por nombre y, si dos productos se llaman igual, por precio de menor a mayor.

usort($catalogo, function (array $a, array $b): int {
    return strcmp($a['nombre'], $b['nombre'])
        ?: $a['precio'] <=> $b['precio'];
});

El operador ?: devuelve el resultado del segundo criterio solo si el primero dio cero, o sea si los nombres son iguales. Es la forma corta de encadenar criterios.

Ejercicio 8

Escribir normalizar() que quite espacios sobrantes, pase a minúsculas y quite los acentos. Usarla para buscar «AZUCAR» en el catálogo.

function normalizar(string $texto): string
{
    $texto = trim($texto);
    $texto = mb_strtolower($texto, 'UTF-8');

    return strtr($texto, [
        'á' => 'a', 'é' => 'e', 'í' => 'i',
        'ó' => 'o', 'ú' => 'u', 'ü' => 'u', 'ñ' => 'n',
    ]);
}

$busqueda = normalizar('AZUCAR');

$encontrados = array_filter(
    $catalogo,
    fn (array $p): bool => str_contains(normalizar($p['nombre']), $busqueda)
);

Se usa mb_strtolower y no strtolower: la versión sin mb_ puede romper las mayúsculas acentuadas.

Ejercicio 9

Convertir la línea '1046;Aceite 900 ml;2450.00;8' en un producto con claves y tipos correctos. Después mostrar cuántos caracteres tiene el nombre, contando el acento como uno.

$linea = '1046;Aceite 900 ml;2450.00;8';
[$codigo, $nombre, $precio, $stock] = explode(';', $linea);

$producto = [
    'codigo' => (int) $codigo,
    'nombre' => trim($nombre),
    'precio' => (float) $precio,
    'stock'  => (int) $stock,
];

echo mb_strlen($producto['nombre']);   // 13

explode devuelve todo como texto. Si el precio queda como '2450.00', la primera multiplicación lo convierte sola, pero cualquier === posterior falla.

Ejercicio 10

Este código intenta calcular el total del stock valorizado. Tiene cinco errores: encontrarlos y corregirlos.

<?php

$catalogo = [
    ['nombre' => 'Yerba', 'precio' => 1850.50, 'stock' => 24],
    ['nombre' => 'Azúcar', 'precio' => 1200, 'stock' => 0],
];

$total = 0;
$ordenado = sort($catalogo)

foreach ($ordenado as $p) {
    $total += $p['precio'] * $p[stock];
}

echo "Total: " . $total;
echo "Productos: " . $catalogo;

Los errores son: falta el punto y coma después de sort(); sort() devuelve un booleano y ordena en el lugar, así que el foreach sobre $ordenado no recorre nada; además sort() no sirve para un array de arrays, habría que usar usort(); la clave stock va sin comillas, que es error fatal; y se hace echo de un array, que produce «Array to string conversion».

La versión corregida:

<?php

declare(strict_types=1);

$total = 0.0;

foreach ($catalogo as $p) {
    $total += $p['precio'] * $p['stock'];
}

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

Cómo saber si está bien

Si fallaste… Volvé a
Las preguntas 1 a 5Por qué funciones, Definir y llamar y Parámetros.
Las preguntas 6 a 10Devolver valores, Ámbito y paso por valor y Declarar los tipos.
Las preguntas 11 a 15Arrays, sobre todo array_filter y las claves.
Las preguntas 16 a 20Las funciones de array que se usan siempre y Ordenar.
Las preguntas 21 a 24Strings y Un caso real: normalizar para buscar.
Los ejercicios 9 y 10Errores frecuentes: son los que juntan todas las trampas en un solo lugar.

Con 18 o más respuestas correctas, la lección está firme. Entre 12 y 17, conviene releer los temas que fallaron antes de seguir. Con menos de 12, la lección 3 va a costar: los formularios y las sesiones se apoyan todo el tiempo en funciones y arrays.

Lo que hay que poder explicar

Idea La respuesta en una línea
Una regla, un lugarLa función se escribe una vez y se llama desde todos lados.
Tipos declaradosMueven el error al lugar donde se produce, no tres pantallas después.
Cláusulas de guardaSe descarta lo inválido primero y el camino normal queda sin anidar.
Los arrays se pasan por valorSi la función los cambia, tiene que devolverlos.
array_filter conserva clavesPara renumerar hace falta array_values.
Ordenar es delicadosort devuelve un booleano; asort conserva claves; usort para arrays de arrays.
in_array con trueSin eso compara con ==, y en permisos eso es un agujero.
mb_* para texto en españolUna letra acentuada ocupa dos bytes.
Normalizar los dos ladosSe normaliza para comparar; se muestra el original, escapado.

La lección 3 toma todo esto y lo pone a trabajar: el primer formulario, el login del vendedor y la sesión que recuerda quién está atendiendo.

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.