Для начала ответим на вопрос буквально:
конечно же, в настройках соединения прописано
PDO::ATTR_EMULATE_PREPARES => false
В этом случае - вообще незачем.
Если эмуляция отключена, то можно вообще никогда не указывать тип.
Правда, насчет "конечно" ты поторопился. Ничего "конечного" в отключении эмуляции нет - оба варианта одинаково безопасные.
И вот если эмуляцию включить, то как раз и возникнет единственный случай, когда придется биндить с указанием типа: если у тебя в запросе передаются параметры в LIMIT. Если в запросе есть оператор LIMIT и в него передаются параметры, то их надо обязательно биндить через PDO::PARAM_INT - иначе запрос выдаст ошибку.
Мало того - передаваемые данные надо самостоятельно привести к типу int - PDO это за тебя делать не будет!
Теперь ответим в общем, объясняя твои многочисленные заблуждения:
- Как тебе уже объяснили выше, инъекция - это не про сохранение в базе. Это именно про выполнение запроса. Так что тип поля в БД не имеет значения.
- Инъекцию через PDO провести нельзя только если на 100% соблюдается условие "любые данные попадают в запрос только через плейсхолдеры" - просто самим фактом своего присутствия PDO ничего ни от кого не защищает. Кстати, соблюдение этого правила не так просто, как кажется. Решение для большинства нетривиальных случаев можно посмотреть здесь: phpfaq.ru/pdo
- Самое важное: если мы используем плейсхолдеры, то все остальное уже неважно. Указывай какой хочешь тип, или не указывай вовсе - инъекции не будет. То есть, к безопасности твой вопрос про указание типа отношения не имеет.
- Если ты не указал тип, то по умолчанию берется PDO::PARAM_STR. Это очень удобно, поскольку БД (по крайней мере - mysql) всегда корректно обработает любые данные, если они переданы, как строки
Так что, я думаю, что ты теперь и сам можешь ответить на вопрос, "зачем указывать тип".
И будешь писать просто
$sth = $dbh->prepare('SELECT * FROM fruit WHERE calories < ? AND colour = ?');
$sth->execute([$_POST['calories'],$_POST['colour']]);