Широко распространенная ошибка: «PHP Parse error: syntax error, unexpected ‘?’ in …» Смысл ее понятен из формулировки — парсер PHP столкнулся с синтаксической ошибкой в скрипте.
В первую очередь, конечно же нужно проверить скрипт или указанную в ошибке его часть, нет ли там действительно опечатки — незакрытая или лишняя скобка, точка, все что угодно.
Если Вы проверили все и уверены в синтаксисе, то следующее, что я рекомендую проверить — это кодировка файла. Откройте скрипт в вашем любимом текстовом редакторе,
я использую notepad++, и проверьте в какой кодировке сохранен файл. Если просто в UTF-8, то в этом может и быть причина.
Дело в том, что при сохранении файла в кодировке UTF-8 в самое начало файла добавляется специальная сигнатура. Называется она BOM — Byte Order Mark, Маркер последовательности байтов.
Фактически это символ(его код U+FEFF), поэтому парсер и начинает разбор синтаксиса с него, а не, например, с открывающего тэга <?php, поэтому для него весь синтаксис и сбивается.
Для решения проблемы нужно просто преобразовать файл в кодировку UTF-8 без BOM, сделать это можно в том же текстовом редакторе.
То же самое можно сделать в командной строке на сервере, если так удобнее.
Смотрим наш скрипт в 16-ричном виде:
# head -n1 AppAsset.php | hexdump -C
00000000 ef bb bf 3c 3f 70 68 70 0a |…<?php.|
00000009
Видим, что перед тэгом <?php есть что-то. В Hex — это сигнатура «ef bb bf», что и указывает на то, что у нас в скрипте есть BOM.
Открываем скрипт в текстовом редакторе Vi, на многих серверах он есть.
# vi AppAsset.php
Далее, пока vi в командном режиме, набираем в нем команду
:set nobomb
Сохраняемся и выходим
:wq
Проверяем еще раз
# head -n1 AppAsset.php | hexdump -C
00000000 3c 3f 70 68 70 0a |<?php.|
00000006
Все отлично.
Проблема с версией PHP
Хотя в некоторых случая причина ошибки может быть не в этом и придется искать дальше.
Опишу мой случай. После переноса сайта на другой хостинг вылетела эта ошибка. Причем парсер остановился именно на символе ‘?’.
Я, на всякий случай, проверил скрипт на наличие опечаток, но все было нормально. Парсер остановился на конструкции
$query = $_SERVER[‘QUERY_STRING’] ?? »;
Вроде бы все нормально, ошибок нет, вполне легально используется оператор ‘??’.
Дело оказалось в том, что изначально сайт был на хостинге с PHP версии 7, а переносился на версию 5.6.
А оператор объединения с null(??) был введен только в 7-й версии PHP, я это упустил.
http://php.net/manual/ru/migration70.new-features.php#migration70.new-features.null-coalesce-op
В итоге, после смены версии на 7-ю все заработало.