prod/native/phpbridge_extension/code/AutoZvalFunctions.cpp (280 lines of code) (raw):

/* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch B.V. licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include "AutoZval.h" #include <php.h> #include <Zend/zend_exceptions.h> #include <functional> static zend_class_entry *autozval_ce; ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_getStringView, 0, 1, IS_STRING, 0) ZEND_ARG_INFO(0, arg) ZEND_END_ARG_INFO() PHP_METHOD(AutoZval, getStringView) { zval *arg; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(arg) ZEND_PARSE_PARAMETERS_END(); try { auto str = elasticapm::php::AutoZval(arg).getStringView(); RETURN_STRINGL(str.data(), str.length()); } catch (std::runtime_error const &e) { zend_throw_exception_ex(NULL, 0, "getStringView exception: %s", e.what()); RETURN_THROWS(); } } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_getLong, 0, 1, IS_LONG, 0) ZEND_ARG_INFO(0, arg) ZEND_END_ARG_INFO() PHP_METHOD(AutoZval, getLong) { zval *arg; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(arg) ZEND_PARSE_PARAMETERS_END(); try { RETURN_LONG(elasticapm::php::AutoZval(arg).getLong()); } catch (std::runtime_error const &e) { zend_throw_exception_ex(NULL, 0, "getLong exception: %s", e.what()); RETURN_THROWS(); } } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_getDouble, 0, 1, IS_DOUBLE, 0) ZEND_ARG_INFO(0, arg) ZEND_END_ARG_INFO() PHP_METHOD(AutoZval, getDouble) { zval *arg; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(arg) ZEND_PARSE_PARAMETERS_END(); try { RETURN_DOUBLE(elasticapm::php::AutoZval(arg).getDouble()); } catch (std::runtime_error const &e) { zend_throw_exception_ex(NULL, 0, "getDouble exception: %s", e.what()); RETURN_THROWS(); } } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_getNumberAsDouble, 0, 1, IS_DOUBLE, 0) ZEND_ARG_INFO(0, arg) ZEND_END_ARG_INFO() PHP_METHOD(AutoZval, getNumberAsDouble) { zval *arg; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(arg) ZEND_PARSE_PARAMETERS_END(); try { RETURN_DOUBLE(elasticapm::php::AutoZval(arg).getNumberAsDouble()); } catch (std::runtime_error const &e) { zend_throw_exception_ex(NULL, 0, "getNumberAsDouble exception: %s", e.what()); RETURN_THROWS(); } } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_getNumberAsLong, 0, 1, IS_LONG, 0) ZEND_ARG_INFO(0, arg) ZEND_END_ARG_INFO() PHP_METHOD(AutoZval, getNumberAsLong) { zval *arg; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(arg) ZEND_PARSE_PARAMETERS_END(); try { RETURN_LONG(elasticapm::php::AutoZval(arg).getNumberAsLong()); } catch (std::runtime_error const &e) { zend_throw_exception_ex(NULL, 0, "getNumberAsLong exception: %s", e.what()); RETURN_THROWS(); } } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_getBoolean, 0, 1, _IS_BOOL, 0) ZEND_ARG_INFO(0, arg) ZEND_END_ARG_INFO() PHP_METHOD(AutoZval, getBoolean) { zval *arg; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(arg) ZEND_PARSE_PARAMETERS_END(); try { RETURN_BOOL(elasticapm::php::AutoZval(arg).getBoolean()); } catch (std::runtime_error const &e) { zend_throw_exception_ex(NULL, 0, "getBoolean exception: %s", e.what()); RETURN_THROWS(); } } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_getArrayCount, 0, 1, IS_LONG, 0) ZEND_ARG_INFO(0, arg) ZEND_END_ARG_INFO() PHP_METHOD(AutoZval, getArrayCount) { zval *arg; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(arg) ZEND_PARSE_PARAMETERS_END(); if (Z_TYPE_P(arg) != IS_ARRAY) { zend_throw_exception(NULL, "Expected array", 0); RETURN_THROWS(); } RETURN_LONG(elasticapm::php::AutoZval(arg).getArrayCount()); } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_setString, 0, 1, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, arg, IS_STRING, 0) ZEND_END_ARG_INFO() PHP_METHOD(AutoZval, setString) { zend_string *arg; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_STR(arg) ZEND_PARSE_PARAMETERS_END(); elasticapm::php::AutoZval az; az.setString({ZSTR_VAL(arg), ZSTR_LEN(arg)}); RETURN_ZVAL(az.get(), 1, 0); } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_setLong, 0, 1, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, arg, IS_LONG, 0) ZEND_END_ARG_INFO() PHP_METHOD(AutoZval, setLong) { zend_long arg; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_LONG(arg) ZEND_PARSE_PARAMETERS_END(); elasticapm::php::AutoZval az; az.setLong(arg); RETURN_ZVAL(az.get(), 1, 0); } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_setNull, 0, 0, IS_NULL, 0) ZEND_END_ARG_INFO() PHP_METHOD(AutoZval, setNull) { elasticapm::php::AutoZval az; az.setNull(); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wuninitialized" RETURN_ZVAL(az.get(), 1, 0); #pragma GCC diagnostic pop } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_setDouble, 0, 1, IS_DOUBLE, 0) ZEND_ARG_TYPE_INFO(0, arg, IS_DOUBLE, 0) ZEND_END_ARG_INFO() PHP_METHOD(AutoZval, setDouble) { double arg; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_DOUBLE(arg) ZEND_PARSE_PARAMETERS_END(); elasticapm::php::AutoZval az; az.setDouble(arg); RETURN_ZVAL(az.get(), 1, 0); } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_arrayInit, 0, 0, IS_ARRAY, 0) ZEND_END_ARG_INFO() PHP_METHOD(AutoZval, arrayInit) { elasticapm::php::AutoZval az; az.arrayInit(); RETURN_ZVAL(az.get(), 1, 0); } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_arrayAddNextWithRef, 0, 2, IS_ARRAY, 0) ZEND_ARG_ARRAY_INFO(0, array, 0) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() PHP_METHOD(AutoZval, arrayAddNextWithRef) { zval *array; zval *value; ZEND_PARSE_PARAMETERS_START(2, 2) Z_PARAM_ARRAY(array) Z_PARAM_ZVAL(value) ZEND_PARSE_PARAMETERS_END(); elasticapm::php::AutoZval az(array); az.arrayAddNextWithRef(value); RETURN_ZVAL(array, 1, 0); } using RecursiveArrayVisitor_t = std::function<void(elasticapm::php::AutoZval const &array, std::function<void(elasticapm::php::AutoZval const &)> const &processElement)>; void iteratePrintAutoZval(elasticapm::php::AutoZval const &val, RecursiveArrayVisitor_t const &arrayVisitor) { auto recurse = [&](elasticapm::php::AutoZval const &v) { iteratePrintAutoZval(v, arrayVisitor); }; switch (val.getType()) { case IS_ARRAY: { std::cout << "array(" << val.getArrayCount() << "): {" << std::endl; arrayVisitor(val, recurse); // for (auto const &element : val) { // iteratePrintAutoZval(element, arrayVisitor); // } std::cout << '}' << std::endl; break; } case IS_LONG: std::cout << "long: " << val.getLong() << std::endl; break; case IS_DOUBLE: std::cout << "double: " << val.getDouble() << std::endl; break; case IS_TRUE: case IS_FALSE: std::cout << "bool: " << val.getBoolean() << std::endl; break; case IS_STRING: std::cout << '\'' << val.getStringView() << '\'' << std::endl; break; case IS_NULL: std::cout << "isNull: " << val.isNull() << std::endl; break; case IS_OBJECT: std::cout << "isObject: " << val.isObject() << std::endl; break; case IS_RESOURCE: std::cout << "isResource: " << val.isResource() << std::endl; break; case IS_UNDEF: std::cout << "isUndef: " << val.isUndef() << std::endl; break; default: std::cout << "unknown type: " << val.getType() << std::endl; } } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_iterateArray, 0, 1, IS_VOID, 0) ZEND_ARG_INFO(0, array) ZEND_END_ARG_INFO() PHP_METHOD(AutoZval, iterateArray) { zval *val; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(val) ZEND_PARSE_PARAMETERS_END(); elasticapm::php::AutoZval value(val); RecursiveArrayVisitor_t arrayVisitor = [](auto const &array, auto const &processElement) { for (auto const &element : array) { processElement(element); } }; iteratePrintAutoZval(value, arrayVisitor); } ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_iterateKeyValueArray, 0, 1, IS_VOID, 0) ZEND_ARG_INFO(0, array) ZEND_END_ARG_INFO() PHP_METHOD(AutoZval, iterateKeyValueArray) { zval *val; ZEND_PARSE_PARAMETERS_START(1, 1) Z_PARAM_ZVAL(val) ZEND_PARSE_PARAMETERS_END(); elasticapm::php::AutoZval value(val); RecursiveArrayVisitor_t arrayVisitor = [](auto const &array, auto const &processElement) { for (auto it = array.kvbegin(); it != array.kvend(); ++it) { auto [key, val] = *it; std::cout << "key: "; if (std::holds_alternative<std::string_view>(key)) { std::cout << '\'' << std::get<std::string_view>(key) << '\''; } else { std::cout << static_cast<zend_long>(std::get<zend_ulong>(key)); } std::cout << " => "; processElement(val); } }; iteratePrintAutoZval(value, arrayVisitor); } // clang-format off static const zend_function_entry autozval_methods[] = { PHP_ME(AutoZval, getStringView, arginfo_getStringView, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_ME(AutoZval, getLong, arginfo_getLong, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_ME(AutoZval, getDouble, arginfo_getDouble, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_ME(AutoZval, getNumberAsDouble, arginfo_getNumberAsDouble, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_ME(AutoZval, getNumberAsLong, arginfo_getNumberAsLong, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_ME(AutoZval, getBoolean, arginfo_getBoolean, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_ME(AutoZval, getArrayCount, arginfo_getArrayCount, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_ME(AutoZval, setString, arginfo_setString, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_ME(AutoZval, setLong, arginfo_setLong, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_ME(AutoZval, setNull, arginfo_setNull, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_ME(AutoZval, setDouble, arginfo_setDouble, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_ME(AutoZval, arrayInit, arginfo_arrayInit, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_ME(AutoZval, arrayAddNextWithRef, arginfo_arrayAddNextWithRef, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_ME(AutoZval, iterateArray, arginfo_iterateArray, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_ME(AutoZval, iterateKeyValueArray, arginfo_iterateKeyValueArray, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) PHP_FE_END }; // clang-format on void register_AutoZval_class() { zend_class_entry ce; INIT_CLASS_ENTRY(ce, "AutoZval", autozval_methods); autozval_ce = zend_register_internal_class(&ce); }