Операторы

This article describes Zephir’s operators. For precedence, you can check the Operator Precedence article.

Zephir’s operators are similar to the ones in PHP, and inherit some of their behaviors.

Арифметические операторы

Поддерживаются следующие операторы:

Операция Пример
Приведение к отрицательному -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") { // or !=
    echo str;
}

Он также может работать как PHP-функция gettype.

return typeof str;

Be careful, if you want to check whether an object is ‘callable’, you always have to use typeof as a comparison operator, not a function.

Подсказки типа

Zephir всегда пытается проверить, реализует ли объект методы и свойства, вызываемые/доступные для переменной, которая выводится как объект:

let o = new MyObject();

// Zephir проверяет, реализован ли "myMethod" в MyObject
o->myMethod();

Однако из-за динамичной природы, унаследованной от PHP, иногда нелегко узнать класс объекта, поэтому Zephir не может эффективно создавать отчеты об ошибках. Подсказка типа сообщает компилятору, какой класс связан с динамической переменной, позволяющей компилятору выполнять больше проверок компиляции:

// Сообщает компилятору, что "o"
// является экземпляром класса MyClass
let o = <MyClass> this->_myObject;
o->myMethod();

Эти «подсказки типов» являются слабыми. Это означает, что программа не проверяет, является ли значение экземпляром указанного класса, и не проверяет реализует ли он указанный интерфейс. Если вы хотите, чтобы это проверялось каждый раз при выполнении, используйте строгую типизацию:

// Always check if the property is an instance
// of MyClass before the assignment
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;
    }
}