php

package
v0.18.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 16, 2026 License: Apache-2.0 Imports: 0 Imported by: 0

README

PHP-биндинги encx

PHP-обёртка над клиентом Encounter из encx. Go-пакет mobile/encxmobile собирается в разделяемую библиотеку (-buildmode=c-shared), а PHP вызывает её через FFI. Клиент живёт на стороне Go, поэтому сессия, куки и HAR-запись сохраняются между вызовами — PHP держит только целочисленный хендл.

Биндинги генерируются из Go-исходника, поэтому его поверхность не может от них убежать незаметно: см. Синхронизация.

Требования

Что Зачем
PHP 8.1+ с расширением ffi загрузка библиотеки и вызовы
Go (версия из go.mod) сборка библиотеки и генерация
Компилятор C (clang/gcc) и CGO_ENABLED=1 cgo-сборка c-shared

Composer не нужен: рядом лежит autoload.php. composer.json есть для тех, кто подключает биндинги как пакет.

Проверить, что FFI доступен:

php -r 'var_dump(extension_loaded("ffi"));'

Сборка

bash bindings/php/build.sh

Скрипт кладёт libencx.dylib (macOS), libencx.so (Linux) или encx.dll (Windows) в bindings/php/lib/. Каталог не версионируется — библиотеку собирают локально или в CI.

Использование

<?php

require __DIR__ . '/bindings/php/autoload.php';

$client = Encx\Client::newClient('demo.en.cx', false);

$login = json_decode($client->login('user', 'password'), true);
if ($login['Error'] !== 0) {
    throw new RuntimeException(Encx\Helpers::loginErrorText($login['Error']));
}

$model = json_decode($client->getGameModel(82448), true);
echo $model['GameTitle'], "\n";

$client->close();

Для домена без TLS (например локальный encx-mock) используйте расширенную фабрику:

$client = Encx\Client::newClientWithOptions('127.0.0.1:18080', false, true, 10, 'ru');

Аргументы: домен, insecureTLS, useHTTP, таймаут в секундах, язык.

Как читать сигнатуры

Имена методов — это Go-имена в lowerCamelCase: GetGameModelgetGameModel, APIBaseURLapiBaseURL, ExportHARexportHAR. Отображение типов:

Go PHP
string string
int64 int
bool bool
[]byte string (бинарная строка; base64 разбирается за вас)
(T, error) T, а ошибка бросается как Encx\EncxException
error void, ошибка бросается
*HARSnapshot array

Методы, возвращающие JSON (login, getGameModel, getProfile, …), отдают строку — разбирайте её json_decode, как это делают Swift/Kotlin с теми же биндингами.

Время жизни клиента

Каждый Client владеет одним хендлом Go-клиента. Вызывайте close(), когда закончили; деструктор делает то же для клиента, переживившего последнее использование. Повторный close() безвреден, а обращение к закрытому клиенту бросает EncxException.

Что связано, а что нет

Связано 49 символов: 2 фабрики, методы *EncClient (игра, коды, команды, профиль, куки, HAR) и 5 статических функций в Encx\Helpers. Полный машиночитаемый список — в bindings.manifest.json.

Не связано 20 символов, и манифест хранит причину для каждого:

  • IsAntiSpamError, AntiSpamURLFromError, IsUndecodableAcceptedError — принимают error. Go-ошибка это интерфейсное значение, у него нет представления в C ABI. Из PHP та же информация доступна через текст сообщения EncxException.
  • EncClient.NewAgentSession, StartCodexDeviceLogin и методы AgentSession и CodexDeviceLogin — это отдельные объекты с внутренним состоянием (мьютексы, провайдеры, делегаты). Реестр хендлов сейчас держит только *EncClient, поэтому агентская часть API остаётся вне биндингов.

Список не поддерживается вручную: он вычисляется из исходника при каждой генерации.

Синхронизация

Из Go-исходника генерируются пять файлов:

Файл Что это
cshared/exports_gen.go cgo-обёртки с //export
encx.h C-заголовок, который читает FFI::cdef
bindings.manifest.json снимок поверхности: связанное и пропущенное с причинами
src/Encx/Client.php класс клиента
src/Encx/Helpers.php пакетные функции

Правки в них не переживут следующую генерацию — каждый помечен DO NOT EDIT. Рукописны только src/Encx/Ffi.php, src/Encx/EncxException.php, cshared/runtime.go и autoload.php: они реализуют механику вызова, а не поверхность API.

Регенерация:

go generate ./bindings/...

Отставание биндингов от кода ловят четыре независимых механизма:

  1. Кодогенерация. Поверхность не пишется руками, поэтому расходиться нечему: bindings/php/cmd/encxphpgen разбирает AST mobile/encxmobile и печатает все пять файлов.

    Отслеживается: какие символы связаны и почему остальные нет, их сигнатуры, их doc-комментарии и форма каждой возвращаемой структуры — вплоть до имён полей, их типов и json-тегов. Тела методов не отслеживаются, и это правильно: переписать реализацию связанного метода, не трогая сигнатуру, — значит оставить биндинги верными.

    Если Go-имя параметра нельзя перенести (совпадает с C-параметром хендла, не может быть PHP-переменной вроде $this), генератор падает с кодом 1 и называет метод и имя, а не выпускает не собирающийся артефакт.

  2. Go-тест. go test ./bindings/... перегенерирует артефакты в память и падает, называя устаревший файл и первую разошедшуюся строку.

  3. CI. .github/workflows/bindings.yml запускает генерацию и падает при непустом git diff по bindings/, затем собирает библиотеку и гоняет e2e.

  4. Pre-commit hook. Устанавливается один раз:

    bash bindings/php/hooks/install.sh
    

    Хук срабатывает только на коммитах, задевающих mobile/encxmobile/ или bindings/php/, перегенерирует биндинги и блокирует коммит с устаревшими файлами. Индекс он не правит: что попадёт в коммит — решение автора, а не хука.

Быстрая проверка актуальности без записи файлов:

cd bindings/php && go run ./cmd/encxphpgen -out . -check

Тесты

go test ./bindings/... -count=1        # генератор, runtime, drift-детектор
bash bindings/php/tests/run-e2e.sh     # сквозной прогон PHP → FFI → Go → encx-mock

E2E-раннер самодостаточен: он собирает библиотеку, поднимает encx-mock на свободном порту, прогоняет tests/e2e.php и гасит сервер. Тест проверяет в том числе, что сессия переживает вызовы, что ошибка Go приходит исключением, а не null, и что []byte ходит через C ABI в обе стороны.

Добавление другого языка

bindings/ рассчитан на несколько языков. Модель поверхности (bindings/php/internal/surface) не зависит от PHP: она описывает пакет mobile/encxmobile в терминах типов, переносимых через C ABI. Новый язык — это новый эмиттер поверх той же модели плюс свой раздел в манифесте.

Documentation

Overview

Package php holds the PHP bindings for encx: a C-shared library built from mobile/encxmobile and the PHP classes that call it through FFI.

The cgo export file, the C header, the surface manifest and the PHP classes are all generated from the Go source of mobile/encxmobile, and a test regenerates them and compares byte for byte, so a change to the bound surface fails the build until they are regenerated. What the model records, and therefore what the drift check sees, is: which symbols are bound and why the rest are not, their signatures, their doc comments, and the shape of every returned struct down to the field names, field types and json tags. Method bodies are not part of it, and deliberately so: reimplementing a bound method without touching its signature leaves the bindings correct.

Run `go generate ./bindings/...` after changing mobile/encxmobile.

Directories

Path Synopsis
cmd
encxphpgen command
Command encxphpgen generates the PHP bindings for encx from the Go source of mobile/encxmobile.
Command encxphpgen generates the PHP bindings for encx from the Go source of mobile/encxmobile.
Command cshared is the c-shared library the PHP bindings load through FFI.
Command cshared is the c-shared library the PHP bindings load through FFI.
internal
gen
Package gen emits the C side of the PHP bindings from a surface.Model: the cgo wrapper file compiled into the c-shared library, the FFI-parsable C header, and a JSON manifest describing what was bound and what was not.
Package gen emits the C side of the PHP bindings from a surface.Model: the cgo wrapper file compiled into the c-shared library, the FFI-parsable C header, and a JSON manifest describing what was bound and what was not.
genphp
Package genphp emits the PHP side of the encx bindings: the Client class wrapping the opaque Go handle, and the Helpers class holding the package-level functions that need no client.
Package genphp emits the PHP side of the encx bindings: the Client class wrapping the opaque Go handle, and the Helpers class holding the package-level functions that need no client.
rt
Package rt provides the hand-written runtime shared by the generated PHP cgo bindings: a handle registry for live *encxmobile.EncClient values and a JSON response envelope.
Package rt provides the hand-written runtime shared by the generated PHP cgo bindings: a handle registry for live *encxmobile.EncClient values and a JSON response envelope.
surface
Package surface models the exported surface of the encxmobile Go package as it can be projected onto a C ABI.
Package surface models the exported surface of the encxmobile Go package as it can be projected onto a C ABI.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL