Операторы
Операторы в Zephir похожи на их аналоги в PHP и также себя ведут.
Арифметические операторы
Поддерживаются следующие операторы:
Операция | Пример |
---|---|
Приведение к отрицательному | -a |
Сложение | a + b |
Вычитание | a - b |
Умножение | a * b |
Деление | a / b |
Деление по модулю | a % b |
Побитовые операторы
Поддерживаются следующие операторы:
Операция | Пример |
---|---|
И | a & b |
Или | a | b |
Исключающее или | a ^ b |
Отрицание | ~a |
Сдвиг влево | a << b |
Сдвиг вправо | a >> b |
Пример:
if a & SOME_FLAG {
echo "Флаг установлен";
}
Узнать больше о сравнении динамических переменных можно из документации по PHP.
Операторы сравнения
Операции сравнения зависят от типа сравниваемых переменных. Например если оба операнда динамические, то результат будет таким же как и в PHP:
Пример | Операция | Описание |
---|---|---|
a == b |
Равенство | true если a равно b после приведения типов. |
a === b |
Идентичность | true если a равно b, и операнды одного типа. |
a != b |
Не равны | true если a не равно b после приведения типов. |
a <> b |
Не равны | true если a не равно b после приведения типов. |
a !== b |
Не идентичны | true если a не равно b после приведения типов. |
a < b |
Меньше чем | true если a строго меньше b. |
a > b |
Больше чем | true если a строго больше b. |
a <= b |
Меньше чем или равно | true если a меньше, или равно b. |
a >= b |
Больше чем или равно | true если a строго больше, или равно b. |
Пример:
if a == b {
return 0;
} else {
if a < b {
return -1;
} else {
return 1;
}
}
Логические операторы
Поддерживаются следующие операторы:
Операция | Пример |
---|---|
И | a && b |
Или | a || b |
Отрицание | !a |
Пример:
if a && b || !c {
return -1;
}
return 1;
Тернарный оператор
Zephir поддерживает тернарный оператор, как в C или PHP:
let b = a == 1 ? "x" : "y"; // b будет присвоен "x", если a равно 1 в противном случае "y"
Специальные операторы
Поддерживаются следующие операторы:
Empty
Этот оператор позволяет узнать пусто ли выражение. Под “пусто” подразумевается выражение равное null
, пустая строка или пустой массив:
let someVar = "";
if empty someVar {
echo "пусто!";
}
let someVar = "привет";
if !empty someVar {
echo "не пусто!";
}
Fetch
Оператор “fetch” создан для сокращения популярной в PHP конструкции:
<?php
if (isset($myArray[$key])) {
$value = $myArray[$key];
echo $value;
}
В Zephir тот же код будет можно написать так:
if fetch value, myArray[key] {
echo value;
}
Оператор “fetch” вернет true
, если в массиве есть что-то по ключу “key” и тогда переменной “value” будет присвоено значение.
Isset
Проверяет, существует ли индекс у массива или свойство у объекта:
let someArray = ["a": 1, "b": 2, "c": 3];
if isset someArray["b"] { // проверим, есть ли у массива индекс "b"
echo "Да, переменная имеет индекс 'b'\n";
}
Использование isset
возможно и в возвращаемых конструкциях:
return isset this->{someProperty};
Обратите внимание, isset
в Zephir работает скорее как array_key_exists в PHP. Иными словами isset
в Zephir вернёт true, даже если значение равно null.
Typeof
Этот оператор проверяет тип переменной. ‘typeof’ может использоваться с оператором сравнения:
if (typeof str == "string") { // или !=
echo str;
}
Он также может работать как PHP-функция gettype
.
return typeof str;
Будьте осторожны, если вы хотите проверить, является ли объект «вызываемым» (callback-функцией), вы всегда должны использовать typeof
в качестве оператора сравнения, а не как функцию.
Подсказки типа
Zephir всегда пытается проверить, реализует ли объект методы и свойства, вызываемые/доступные для переменной, которая выводится как объект:
let o = new MyObject();
// Zephir проверяет, реализован ли "myMethod" в MyObject
o->myMethod();
Однако из-за динамичной природы, унаследованной от PHP, иногда нелегко узнать класс объекта, поэтому Zephir не может эффективно создавать отчеты об ошибках. Подсказка типа сообщает компилятору, какой класс связан с динамической переменной, позволяющей компилятору выполнять больше проверок компиляции:
// Сообщает компилятору, что "o"
// является экземпляром класса MyClass
let o = <MyClass> this->_myObject;
o->myMethod();
Эти «подсказки типов» являются слабыми. Это означает, что программа не проверяет, является ли значение экземпляром указанного класса, и не проверяет реализует ли он указанный интерфейс. Если вы хотите, чтобы это проверялось каждый раз при выполнении, используйте строгую типизацию:
// Проверяем, является ли свойство экземпляром
// класса MyClass перед присваиванием
let o = <MyClass!> this->_myObject;
o->myMethod();
Подсказки прогнозирования ветвлений
Что такое прогнозирование ветвлений? Для подробного описания это понятия обратитесь к статье Игоря Островского или описанию на Wikipedia. В окружениях, где производительность является очень важной составляющей, может оказаться полезным использование подсказок при прогнозировании ветвлений.
Рассмотрим следующий пример:
let allPaths = [];
for path in this->_paths {
if path->isAllowed() == false {
throw new App\Exception("Некое сообщение об ошибке");
} else {
let allPaths[] = path;
}
}
Авторы кода, приведенного выше, заранее знают, что условие, которое выбрасывает исключение, вряд ли произойдет. Это означает, что в 99.9% случаев наш метод выполняет эту проверку в холостую — условие вероятно не будет оцениваться как истинное. Но для процессора, обычно, это сложно понять, поэтому мы могли бы ввести здесь подсказку:
let allPaths = [];
for path in this->_paths {
if unlikely path->isAllowed() == false {
throw new App\Exception("Некое сообщение об ошибке");
} else {
let allPaths[] = path;
}
}