Эта ошибка возникает в двух вариантах:
$arr = [1, 2, 3];
Синтаксис инициализатора этого массива был введен только в PHP 5.4; это приведет к возникновению ошибки парсера в версиях до этого. Если возможно, обновите свою установку или используйте старый синтаксис:
$arr = array(1, 2, 3);
См. Также этот пример из руководства.
$suffix = explode(',', 'foo,bar')[1];
Результаты функции разыменования массива также были введены в PHP 5.4. Если обновление невозможно, вам нужно использовать временную переменную:
$parts = explode(',', 'foo,bar');
$suffix = $parts[1];
См. Также этот пример из руководства.
Вместо предположения я решил на самом деле посмотреть на сгенерированный код с маленькой частью кода C++ и несколько старой установки Linux.
class MyException
{
public:
MyException() { }
~MyException() { }
};
void my_throwing_function(bool throwit)
{
if (throwit)
throw MyException();
}
void another_function();
void log(unsigned count);
void my_catching_function()
{
log(0);
try
{
log(1);
another_function();
log(2);
}
catch (const MyException& e)
{
log(3);
}
log(4);
}
Я скомпилировал его с g++ -m32 -W -Wall -O3 -save-temps -c
, и посмотревший сгенерированный файл блока.
.file "foo.cpp"
.section .text._ZN11MyExceptionD1Ev,"axG",@progbits,_ZN11MyExceptionD1Ev,comdat
.align 2
.p2align 4,,15
.weak _ZN11MyExceptionD1Ev
.type _ZN11MyExceptionD1Ev, @function
_ZN11MyExceptionD1Ev:
.LFB7:
pushl %ebp
.LCFI0:
movl %esp, %ebp
.LCFI1:
popl %ebp
ret
.LFE7:
.size _ZN11MyExceptionD1Ev, .-_ZN11MyExceptionD1Ev
_ZN11MyExceptionD1Ev
MyException::~MyException()
, таким образом, компилятор решил, что ему была нужна невстроенная копия деструктора.
.globl __gxx_personality_v0
.globl _Unwind_Resume
.text
.align 2
.p2align 4,,15
.globl _Z20my_catching_functionv
.type _Z20my_catching_functionv, @function
_Z20my_catching_functionv:
.LFB9:
pushl %ebp
.LCFI2:
movl %esp, %ebp
.LCFI3:
pushl %ebx
.LCFI4:
subl $20, %esp
.LCFI5:
movl $0, (%esp)
.LEHB0:
call _Z3logj
.LEHE0:
movl $1, (%esp)
.LEHB1:
call _Z3logj
call _Z16another_functionv
movl $2, (%esp)
call _Z3logj
.LEHE1:
.L5:
movl $4, (%esp)
.LEHB2:
call _Z3logj
addl $20, %esp
popl %ebx
popl %ebp
ret
.L12:
subl $1, %edx
movl %eax, %ebx
je .L16
.L14:
movl %ebx, (%esp)
call _Unwind_Resume
.LEHE2:
.L16:
.L6:
movl %eax, (%esp)
call __cxa_begin_catch
movl $3, (%esp)
.LEHB3:
call _Z3logj
.LEHE3:
call __cxa_end_catch
.p2align 4,,3
jmp .L5
.L11:
.L8:
movl %eax, %ebx
.p2align 4,,6
call __cxa_end_catch
.p2align 4,,6
jmp .L14
.LFE9:
.size _Z20my_catching_functionv, .-_Z20my_catching_functionv
.section .gcc_except_table,"a",@progbits
.align 4
.LLSDA9:
.byte 0xff
.byte 0x0
.uleb128 .LLSDATT9-.LLSDATTD9
.LLSDATTD9:
.byte 0x1
.uleb128 .LLSDACSE9-.LLSDACSB9
.LLSDACSB9:
.uleb128 .LEHB0-.LFB9
.uleb128 .LEHE0-.LEHB0
.uleb128 0x0
.uleb128 0x0
.uleb128 .LEHB1-.LFB9
.uleb128 .LEHE1-.LEHB1
.uleb128 .L12-.LFB9
.uleb128 0x1
.uleb128 .LEHB2-.LFB9
.uleb128 .LEHE2-.LEHB2
.uleb128 0x0
.uleb128 0x0
.uleb128 .LEHB3-.LFB9
.uleb128 .LEHE3-.LEHB3
.uleb128 .L11-.LFB9
.uleb128 0x0
.LLSDACSE9:
.byte 0x1
.byte 0x0
.align 4
.long _ZTI11MyException
.LLSDATT9:
Удивление! Нет никаких дополнительных инструкций вообще относительно нормального пути выполнения кода. Компилятор вместо этого генерировал дополнительные исключительные fixup блоки кода, на которые ссылаются через таблицу в конце функции (который на самом деле помещается на отдельный участок исполняемого файла). Вся работа сделана негласно стандартной библиотекой, на основе этих таблиц (_ZTI11MyException
typeinfo for MyException
).
Хорошо, это не было на самом деле удивлением для меня, я уже знал, как этот компилятор сделал это. Продолжать блок произвело:
.text
.align 2
.p2align 4,,15
.globl _Z20my_throwing_functionb
.type _Z20my_throwing_functionb, @function
_Z20my_throwing_functionb:
.LFB8:
pushl %ebp
.LCFI6:
movl %esp, %ebp
.LCFI7:
subl $24, %esp
.LCFI8:
cmpb $0, 8(%ebp)
jne .L21
leave
ret
.L21:
movl $1, (%esp)
call __cxa_allocate_exception
movl $_ZN11MyExceptionD1Ev, 8(%esp)
movl $_ZTI11MyException, 4(%esp)
movl %eax, (%esp)
call __cxa_throw
.LFE8:
.size _Z20my_throwing_functionb, .-_Z20my_throwing_functionb
Здесь мы видим код для выдачи исключения. В то время как не было никаких дополнительных издержек просто, потому что исключение могло бы быть выдано, существует, очевидно, много издержек в фактическом броске и ловле исключения. Большая часть из него скрыта в __cxa_throw
, который должен:
Сравните это со стоимостью простого возвращения значения, и Вы видите, почему исключения должны использоваться только для исключительных возвратов.
В заключение, остальная часть файла блока:
.weak _ZTI11MyException
.section .rodata._ZTI11MyException,"aG",@progbits,_ZTI11MyException,comdat
.align 4
.type _ZTI11MyException, @object
.size _ZTI11MyException, 8
_ZTI11MyException:
.long _ZTVN10__cxxabiv117__class_type_infoE+8
.long _ZTS11MyException
.weak _ZTS11MyException
.section .rodata._ZTS11MyException,"aG",@progbits,_ZTS11MyException,comdat
.type _ZTS11MyException, @object
.size _ZTS11MyException, 14
_ZTS11MyException:
.string "11MyException"
typeinfo данные.
.section .eh_frame,"a",@progbits
.Lframe1:
.long .LECIE1-.LSCIE1
.LSCIE1:
.long 0x0
.byte 0x1
.string "zPL"
.uleb128 0x1
.sleb128 -4
.byte 0x8
.uleb128 0x6
.byte 0x0
.long __gxx_personality_v0
.byte 0x0
.byte 0xc
.uleb128 0x4
.uleb128 0x4
.byte 0x88
.uleb128 0x1
.align 4
.LECIE1:
.LSFDE3:
.long .LEFDE3-.LASFDE3
.LASFDE3:
.long .LASFDE3-.Lframe1
.long .LFB9
.long .LFE9-.LFB9
.uleb128 0x4
.long .LLSDA9
.byte 0x4
.long .LCFI2-.LFB9
.byte 0xe
.uleb128 0x8
.byte 0x85
.uleb128 0x2
.byte 0x4
.long .LCFI3-.LCFI2
.byte 0xd
.uleb128 0x5
.byte 0x4
.long .LCFI5-.LCFI3
.byte 0x83
.uleb128 0x3
.align 4
.LEFDE3:
.LSFDE5:
.long .LEFDE5-.LASFDE5
.LASFDE5:
.long .LASFDE5-.Lframe1
.long .LFB8
.long .LFE8-.LFB8
.uleb128 0x4
.long 0x0
.byte 0x4
.long .LCFI6-.LFB8
.byte 0xe
.uleb128 0x8
.byte 0x85
.uleb128 0x2
.byte 0x4
.long .LCFI7-.LCFI6
.byte 0xd
.uleb128 0x5
.align 4
.LEFDE5:
.ident "GCC: (GNU) 4.1.2 (Ubuntu 4.1.2-0ubuntu4)"
.section .note.GNU-stack,"",@progbits
Еще больше таблиц обработки исключений и различной дополнительной информации.
Так, заключение, по крайней мере, для GCC на Linux: стоимость является дополнительным пространством (для обработчиков и таблиц), выдаются ли исключения плюс дополнительные расходы парсинга таблиц и выполнения обработчиков, когда исключение выдается. Если Вы используете исключения вместо кодов ошибок, и ошибка редка, это может быть быстрее, так как у Вас нет издержек тестирования на ошибки больше.
В случае, если Вы хотите больше информации, в особенности что весь __cxa_
функции делают, видят исходную спецификацию, из которой они произошли:
Исключения, являющиеся медленным , были верны в былые времена.
В самом современном компиляторе это больше не сохраняется.
Примечание: Просто, потому что у нас есть исключения, не означает, что мы не используем коды ошибки также. Когда ошибка может быть обработана локально коды ошибки использования. Когда ошибки требуют большего количества контекста для исключений использования исправления: Я записал его намного более красноречиво здесь: , Что принципы ведут Вашу политику обработки исключений?
стоимость кода обработки исключений, когда никакие исключения не используются, является практически нулевой.
, Когда исключение выдается, существует некоторая сделанная работа.
, Но необходимо сравнить это со стоимостью возврата кодов ошибки и проверки их полностью назад к указать, где ошибка может быть обработана. И более трудоемкий, чтобы записать и поддержать.
Также существует один глюк для новичков:
, Хотя Объекты исключения, как предполагается, являются небольшими, некоторые люди помещают много материала в них. Тогда у Вас есть стоимость копирования объекта исключения. Решение там два, свернитесь:
, По-моему, я держал бы пари, что тот же код за исключениями или более эффективен или по крайней мере так же сопоставим как код без исключений (но имеет весь дополнительный код для проверки функциональных ошибочных результатов). Помните, что Вы ничего не получаете бесплатно, что компилятор генерирует код, который необходимо было записать во-первых для проверки кодов ошибки (и обычно компилятор намного более эффективен, чем человек).
Существует много способов, которыми Вы могли реализовать исключения, но обычно они будут полагаться на некоторую базовую поддержку со стороны ОС. В Windows это - структурированный механизм обработки исключений.
существует достойное обсуждение деталей о Проекте Кода: , Как компилятор C++ реализует обработку исключений
, издержки исключений происходят, потому что компилятор должен генерировать код для отслеживания, которых объекты должны быть разрушены в каждом стековом фрейме (или более точно определить объем), если исключение распространяет из того объема. Если функция не имеет никаких локальных переменных на стеке, которые требуют, чтобы деструкторы были названы тогда, это не должно иметь потери производительности wrt обработка исключений.
Используя код возврата может только раскрутить единственный уровень стека за один раз, тогда как механизм обработки исключений может перейти, гораздо дальше отодвигают стек в одной операции, если нет ничего для него, чтобы сделать в промежуточных стековых фреймах.
Matt Pietrek написал превосходную статью о Win32 Структурированная Обработка исключений . В то время как эта статья была первоначально написана в 1997, она все еще применяется сегодня (но конечно только относится к Windows).
Эта статья исследует проблему и в основном находит, что на практике существует стоимость во время выполнения для исключений, хотя стоимость является довольно низкой, если исключение не выдается. Хорошая статья, рекомендуемая.
Друг меня записал немного, как Visual C++ обрабатывает исключения несколько лет назад.
Все хорошие ответы.
кроме того, думайте о том, насколько легче это должно отладить код, который делает 'если проверки' как логические элементы наверху методов вместо того, чтобы позволить коду выдавать исключения.
Мой девиз - то, что легко записать код, который работает. Самая важная вещь состоит в том, чтобы записать код для следующего человека, который смотрит на него. В некоторых случаях это - Вы за 9 месяцев, и Вы не хотите проклинать свое имя!