2015-05-02 1 views
3

У меня есть необходимость определить, является ли регулярное выражение действительным, так что недействительные могут быть изящно отвергнуты в пользовательском интерфейсе. При переполнении стека есть a clever abomination, чтобы сделать это с помощью другого регулярного выражения, которое я планирую усиленно избегать.Можно ли пропустить ошибки разделителя в preg/PHP regexp программно?

Существует гораздо более простой подход running a match and checking for errors, который возвращает правильный логический результат, но интересно было бы получить отказ причину/сообщение, а также:

// The error is that preg delimiters are missing 
$testRegex = 'Location: (.+)'; 

// This bit is fine 
$result = preg_match($testRegex, ''); // returns false i.e. failure 
$valid = is_int($result); // false, i.e. the regex is invalid 

// Returns PREG_NO_ERROR, which means no error occured 
echo preg_last_error() . "\n"; 

Если я запускаю это я правильно получить:

PHP Warning: preg_match(): разделительный не должно быть алфавитно-цифровой или обратной косой черты в ... на линии ...

Однако выход функции ошибки равен 0, что равно PREG_NO_ERROR. Я бы подумал, что это вернет ненулевой код ошибки - и было бы еще лучше, если я смогу получить чистую версию предупреждающего сообщения.

Возможно, что это вообще не доступно (т. Е. Доступно только для механизма PHP для печати предупреждения). Я бегу 5.5.3-1ubuntu2.6 (cli).

+0

Создайте свой собственный обработчик ошибок, будет ли это вариант? – Rizier123

+2

Я полагаю, что 'preg_last_error' ничего не возвращает, потому что в этом конкретном случае шаблон регулярных выражений даже не попал в механизм PCRE. Разделители шаблонов заданы PHP, и сам PCRE их не ожидает. PHP удаляет разделители из шаблона и передает * это * в PCRE. Попробуйте использовать недопустимый шаблон, но с разделителями, и посмотрите, возвращает ли 'preg_last_error' что-то значимое. –

+0

@ Лукас, спасибо - это похоже на точный обзор того, что происходит. – halfer

ответ

2

Это должно работать для вас:

Здесь я просто включить буферизацию вывода с ob_start(). Затем я фиксирую последнюю ошибку с error_get_last(). Затем я завершаю буферизацию вывода ob_end_clean(). После этого вы можете проверить, пуст ли массив и если не произошла ошибка.

ob_start(); 
$result = preg_match(".*", "Location: xy"); 
$error = error_get_last(); 
ob_end_clean(); 

if(!empty($error)) 
    echo "<b>Error:</b> " . $error["message"]; 
else 
    echo "no error found!"; 

выход:

 
Error: preg_match(): No ending delimiter '.' found 

EDIT:

Если вы хотите, вы можете создать свой собственный обработчик ошибок, который в основном просто выбрасывает исключение для каждой ошибки, которые вы обычно получаете.

Затем вы можете поместить свой код в блок try - catch и поймать исключение.

set_error_handler(function($errno, $errstr, $errfile, $errline, array $errcontext) { 
    // error was suppressed with the @-operator 
    if (0 === error_reporting()) { 
     return false; 
    } 
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline); 
}); 

try { 
    $result = preg_match(".*", "Location: xy"); 
} catch(Exception $e) { 
    echo "<b>Error:</b> " . $e->getMessage(); 
} 

Код для обработчика ошибок от Philippe Gerber в этом answer

+0

Очень креативное решение, спасибо! Оказывается, есть функция PHP, чтобы сделать это напрямую - см. Ответ Ивана. Не знаю, как я не знал об этом ... ':-)' – halfer

+0

@halfer Будет ли обработчик ошибок также в порядке, потому что тогда вы можете сделать это намного проще? – Rizier123

+0

@halfer * Оказывается, есть функция PHP, чтобы сделать это напрямую * Если вы имеете в виду 'error_get_last()'? Я использую то же самое в своем коде ^. – Rizier123

1

Может быть, вы могли бы использовать error_get_last(), чтобы получить немного больше информации.

Array 
(
    [type] => 2 
    [message] => preg_match(): Delimiter must not be alphanumeric or backslash 
    [file] => /Users/ivan/Desktop/test.php 
    [line] => 6 
) 

type является E_WARNING и вы можете смело предположить имя функции строки из message части, так как он всегда будет находиться в том же формате.

Вы можете сделать

$lastError = error_get_last()['message']; // php 5.5 expression 
if(strpos($lastError, 'preg_match(): ') === 0){ 
    $error = substr($lastError, 14); 
} 

И $error будет var_dump «Эда

string(47) "Delimiter must not be alphanumeric or backslash" 

Или null

Кроме того, в ответ на другой ответ, вы можете surpress предупреждений, используя @preg_match(...), поэтому вам не нужно самостоятельно обрабатывать выходные буферы. error_get_last() все равно поймает ошибку.

+0

Как я использую PHP около десяти лет и не знал об этой функции? Очень удобно - и в этом случае он очень хорошо работает. Благодаря! – halfer

+0

Это случается со всеми, я рад, что смогу помочь. –

Смежные вопросы