├── .gitignore ├── README.md ├── build.sh ├── config.m4 ├── include ├── error.h └── stringappend.h ├── php_rocksdb.h ├── rebuild.sh ├── rocksdb_db.cc ├── rocksdb_exception.cc ├── rocksdb_iterator.cc ├── rocksdb_options.cc ├── rocksdb_snapshot.cc ├── rocksdb_transaction.cc ├── rocksdb_transaction_db.cc ├── rocksdb_write_batch.cc ├── src └── stringappend.cc ├── test.php └── tests ├── CONTRIBUTION ├── README.md ├── clean ├── include ├── bootstrap.php └── lib │ ├── src │ └── Assert.php │ └── vendor │ └── autoload.php ├── new ├── rocksdb_db ├── close.phpt ├── del.phpt ├── deleteRange.phpt ├── destroyDB.phpt ├── get.phpt ├── iterator.phpt ├── keyExist.phpt ├── keyMayExist.phpt ├── open.phpt ├── open_read_only.phpt ├── put.phpt └── write.phpt ├── rocksdb_exception └── throw_rocksdb_exception.phpt ├── rocksdb_transaction_db ├── commit.phpt └── snapshot.phpt ├── run-tests ├── start.sh └── template /.gitignore: -------------------------------------------------------------------------------- 1 | *.lo 2 | *.la 3 | .libs 4 | acinclude.m4 5 | aclocal.m4 6 | autom4te.cache 7 | build 8 | config.guess 9 | config.h 10 | config.h.in 11 | config.log 12 | config.nice 13 | config.status 14 | config.sub 15 | configure 16 | configure.ac 17 | configure.in 18 | install-sh 19 | libtool 20 | ltmain.sh 21 | Makefile 22 | Makefile.fragments 23 | Makefile.global 24 | Makefile.objects 25 | missing 26 | mkinstalldirs 27 | modules 28 | run-tests.php 29 | tests/*/*.diff 30 | tests/*/*.out 31 | /tests/rocksdb_*/*.php 32 | tests/*/*.exp 33 | tests/*/*.log 34 | tests/*/*.sh 35 | .vscode 36 | debug 37 | tmp -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | **A PHP extension for Facebook's RocksDB.** 4 | 5 | ## Example 6 | 7 | You can find all the examples in the tests folder. For better programming, you can install the ide helper that we provide: 8 | 9 | ```bash 10 | composer require hantaohuang/rocksdb-ide-helper --dev 11 | ``` 12 | 13 | ## Installation 14 | 15 | ### Compiling requirements 16 | 17 | 1. Linux, OS X or Cygwin, WSL 18 | 2. PHP 7.0.0 or later 19 | 3. GCC 4.8 or later 20 | 21 | ### Install from source 22 | 23 | ```bash 24 | git clone https://github.com/huanghantao/php-rocksdb.git && \ 25 | cd php-rocksdb && \ 26 | phpize && \ 27 | ./configure && \ 28 | make && make install 29 | ``` 30 | 31 | #### Enable extension in PHP 32 | 33 | After compiling and installing to the system successfully, you have to add a new line extension=rocksdb.so to php.ini to enable rocksdb extension. 34 | 35 | ## Bug 36 | 37 | You can feedback through issues, and we will reply within 24 hours. 38 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | make && make install -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | PHP_ARG_ENABLE(rocksdb, rocksdb support, 2 | [ --enable-rocksdb Enable rocksdb support], [enable_rocksdb="yes"]) 3 | 4 | PHP_ARG_ENABLE(asan, enable asan, 5 | [ --enable-asan Enable asan], no, no) 6 | 7 | PHP_ARG_ENABLE(gcov, enable gcov, 8 | [ --enable-gcov Enable gcov], no, no) 9 | 10 | AC_DEFUN([ROCKSDB_HAVE_PHP_EXT], [ 11 | extname=$1 12 | haveext=$[PHP_]translit($1,a-z_-,A-Z__) 13 | 14 | AC_MSG_CHECKING([for ext/$extname support]) 15 | if test -x "$PHP_EXECUTABLE"; then 16 | grepext=`$PHP_EXECUTABLE -m | $EGREP ^$extname\$` 17 | if test "$grepext" = "$extname"; then 18 | [PHP_HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__)=1 19 | AC_MSG_RESULT([yes]) 20 | $2 21 | else 22 | [PHP_HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__)= 23 | AC_MSG_RESULT([no]) 24 | $3 25 | fi 26 | elif test "$haveext" != "no" && test "x$haveext" != "x"; then 27 | [PHP_HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__)=1 28 | AC_MSG_RESULT([yes]) 29 | $2 30 | else 31 | [PHP_HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__)= 32 | AC_MSG_RESULT([no]) 33 | $3 34 | fi 35 | ]) 36 | 37 | AC_MSG_CHECKING([if compiling with clang]) 38 | AC_COMPILE_IFELSE([ 39 | AC_LANG_PROGRAM([], [[ 40 | #ifndef __clang__ 41 | not clang 42 | #endif 43 | ]])], 44 | [CLANG=yes], [CLANG=no] 45 | ) 46 | AC_MSG_RESULT([$CLANG]) 47 | 48 | if test "$CLANG" = "yes"; then 49 | CFLAGS="$CFLAGS -std=gnu89" 50 | fi 51 | 52 | AC_CANONICAL_HOST 53 | 54 | if test "$PHP_ROCKSDB" != "no"; then 55 | 56 | PHP_ADD_LIBRARY(pthread) 57 | PHP_SUBST(ROCKSDB_SHARED_LIBADD) 58 | 59 | AC_ARG_ENABLE(debug, 60 | [ --enable-debug, compile with debug symbols], 61 | [PHP_DEBUG=$enableval], 62 | [PHP_DEBUG=0] 63 | ) 64 | 65 | if test "$PHP_DEBUG_LOG" != "no"; then 66 | AC_DEFINE(ROCKSDB_DEBUG, 1, [do we enable rocksdb debug]) 67 | PHP_DEBUG=1 68 | fi 69 | 70 | if test "$PHP_ASAN" != "no"; then 71 | PHP_DEBUG=1 72 | CFLAGS="$CFLAGS -fsanitize=address -fno-omit-frame-pointer" 73 | CXXFLAGS="$CXXFLAGS -fsanitize=address -fno-omit-frame-pointer" 74 | fi 75 | 76 | if test "$PHP_GCOV" != "no"; then 77 | PHP_DEBUG=1 78 | CFLAGS="$CFLAGS -fprofile-arcs -ftest-coverage" 79 | CXXFLAGS="$CXXFLAGS -fprofile-arcs -ftest-coverage" 80 | fi 81 | 82 | AS_CASE([$host_os], 83 | [darwin*], [ROCKSDB_OS="MAC"], 84 | [cygwin*], [ROCKSDB_OS="CYGWIN"], 85 | [mingw*], [ROCKSDB_OS="MINGW"], 86 | [linux*], [ROCKSDB_OS="LINUX"], 87 | [] 88 | ) 89 | 90 | CFLAGS="-Wall -pthread $CFLAGS" 91 | LDFLAGS="$LDFLAGS -lpthread" 92 | 93 | if test "$ROCKSDB_OS" = "MAC"; then 94 | AC_CHECK_LIB(c, clock_gettime, AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [have clock_gettime])) 95 | else 96 | AC_CHECK_LIB(rt, clock_gettime, AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [have clock_gettime])) 97 | PHP_ADD_LIBRARY(rt, 1, ROCKSDB_SHARED_LIBADD) 98 | fi 99 | if test "$ROCKSDB_OS" = "LINUX"; then 100 | LDFLAGS="$LDFLAGS -z now" 101 | fi 102 | 103 | PHP_ADD_LIBRARY_WITH_PATH(rocksdb, /usr/local/lib/, ROCKSDB_SHARED_LIBADD) 104 | 105 | PHP_ADD_LIBRARY(pthread, 1, ROCKSDB_SHARED_LIBADD) 106 | 107 | rocksdb_source_file=" \ 108 | rocksdb_db.cc \ 109 | rocksdb_options.cc \ 110 | rocksdb_transaction_db.cc \ 111 | rocksdb_transaction.cc \ 112 | rocksdb_snapshot.cc \ 113 | rocksdb_exception.cc \ 114 | rocksdb_iterator.cc \ 115 | rocksdb_write_batch.cc 116 | " 117 | 118 | PHP_NEW_EXTENSION(rocksdb, $rocksdb_source_file, $ext_shared,,, cxx) 119 | 120 | PHP_ADD_INCLUDE([$ext_srcdir]) 121 | PHP_ADD_INCLUDE([$ext_srcdir/include]) 122 | 123 | PHP_INSTALL_HEADERS([ext/rocksdb], [*.h config.h include/*.h]) 124 | 125 | PHP_REQUIRE_CXX() 126 | 127 | CXXFLAGS="$CXXFLAGS -Wall -Wno-unused-function -Wno-deprecated -Wno-deprecated-declarations" 128 | 129 | if test "$ROCKSDB_OS" = "CYGWIN" || test "$ROCKSDB_OS" = "MINGW"; then 130 | CXXFLAGS="$CXXFLAGS -std=gnu++11" 131 | else 132 | CXXFLAGS="$CXXFLAGS -std=c++11" 133 | fi 134 | fi 135 | -------------------------------------------------------------------------------- /include/error.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum rocksdbErrorCode 4 | { 5 | ROCKSDB_ERROR_BEGIN = 500, 6 | ROCKSDB_OPEN_ERROR, 7 | ROCKSDB_PUT_ERROR, 8 | ROCKSDB_WRITE_ERROR, 9 | ROCKSDB_GET_ERROR, 10 | ROCKSDB_DELETE_ERROR, 11 | ROCKSDB_DELETE_RANGE_ERROR, 12 | ROCKSDB_CLOSE_ERROR, 13 | ROCKSDB_DESTROY_ERROR, 14 | ROCKSDB_BATCH_DELETE_ERROR, 15 | ROCKSDB_COMMIT_ERROR, 16 | ROCKSDB_ROLLBACK_ERROR, 17 | }; -------------------------------------------------------------------------------- /include/stringappend.h: -------------------------------------------------------------------------------- 1 | /** 2 | * A MergeOperator for rocksdb that implements string append. 3 | * @author Deon Nicholas (dnicholas@fb.com) 4 | * Copyright 2013 Facebook 5 | */ 6 | 7 | #pragma once 8 | #include "rocksdb/merge_operator.h" 9 | #include "rocksdb/slice.h" 10 | 11 | namespace rocksdb { 12 | 13 | class StringAppendOperator : public AssociativeMergeOperator { 14 | public: 15 | // Constructor: specify delimiter 16 | explicit StringAppendOperator(char delim_char); 17 | 18 | virtual bool Merge(const Slice& key, 19 | const Slice* existing_value, 20 | const Slice& value, 21 | std::string* new_value, 22 | Logger* logger) const override; 23 | 24 | virtual const char* Name() const override; 25 | 26 | private: 27 | char delim_; // The delimiter is inserted between elements 28 | 29 | }; 30 | 31 | } // namespace rocksdb 32 | -------------------------------------------------------------------------------- /php_rocksdb.h: -------------------------------------------------------------------------------- 1 | /* rocksdb extension for PHP */ 2 | 3 | #ifndef PHP_ROCKSDB_H 4 | # define PHP_ROCKSDB_H 5 | 6 | #include "php.h" 7 | #include "ext/standard/info.h" 8 | #include "zend_exceptions.h" 9 | #include "zend_interfaces.h" 10 | 11 | # define PHP_ROCKSDB_VERSION "0.5.1" 12 | 13 | extern zend_module_entry rocksdb_module_entry; 14 | # define phpext_rocksdb_ptr &rocksdb_module_entry 15 | 16 | void php_rocksdb_exception_minit(int module_number); 17 | void php_rocksdb_iterator_minit(int module_number); 18 | void php_rocksdb_write_batch_minit(int module_number); 19 | void php_rocksdb_transaction_db_minit(int module_number); 20 | void php_rocksdb_transaction_minit(int module_number); 21 | void php_rocksdb_snapshot_minit(int module_number); 22 | 23 | #ifndef ZEND_THIS 24 | #define ZEND_THIS (&EX(This)) 25 | #endif 26 | 27 | extern zend_class_entry *rocksdb_exception_ce; 28 | extern zend_object_handlers rocksdb_exception_handlers; 29 | 30 | extern zend_class_entry *rocksdb_iterator_ce; 31 | extern zend_object_handlers rocksdb_iterator_handlers; 32 | 33 | extern zend_class_entry *rocksdb_transaction_ce; 34 | 35 | #define php_rocksdb_array_get_value(ht, str, v) ((v = zend_hash_str_find(ht, str, sizeof(str)-1)) && !ZVAL_IS_NULL(v)) 36 | 37 | #define ROCKSDB_SET_CLASS_CREATE(module, _create_object) \ 38 | module##_ce->create_object = _create_object 39 | 40 | #define ROCKSDB_SET_CLASS_FREE(module, _free_obj) \ 41 | module##_handlers.free_obj = _free_obj 42 | 43 | #define ROCKSDB_SET_CLASS_CREATE_AND_FREE(module, _create_object, _free_obj) \ 44 | ROCKSDB_SET_CLASS_CREATE(module, _create_object); \ 45 | ROCKSDB_SET_CLASS_FREE(module, _free_obj) 46 | 47 | #define ROCKSDB_SET_CLASS_CUSTOM_OBJECT(module, _create_object, _free_obj, _struct, _std) \ 48 | ROCKSDB_SET_CLASS_CREATE_AND_FREE(module, _create_object, _free_obj); \ 49 | module##_handlers.offset = XtOffsetOf(_struct, _std) 50 | 51 | #define ROCKSDB_Z_OBJCE_NAME_VAL_P(zobject) ZSTR_VAL(Z_OBJCE_P(zobject)->name) 52 | 53 | #if PHP_VERSION_ID < 70300 54 | /* Allocates object type and zeros it, but not the properties. 55 | * Properties MUST be initialized using object_properties_init(). */ 56 | static inline void *zend_object_alloc(size_t obj_size, zend_class_entry *ce) 57 | { 58 | void *obj = emalloc(obj_size + zend_object_properties_size(ce)); 59 | /* Subtraction of sizeof(zval) is necessary, because zend_object_properties_size() may be 60 | * -sizeof(zval), if the object has no properties. */ 61 | memset(obj, 0, obj_size - sizeof(zval)); 62 | return obj; 63 | } 64 | #endif 65 | 66 | /* PHP 7 class declaration macros */ 67 | 68 | static inline int rocksdb_zend_register_class_alias(const char *name, size_t name_len, zend_class_entry *ce) 69 | { 70 | zend_string *_name; 71 | if (name[0] == '\\') 72 | { 73 | _name = zend_string_init(name, name_len, 1); 74 | zend_str_tolower_copy(ZSTR_VAL(_name), name + 1, name_len - 1); 75 | } 76 | else 77 | { 78 | _name = zend_string_init(name, name_len, 1); 79 | zend_str_tolower_copy(ZSTR_VAL(_name), name, name_len); 80 | } 81 | 82 | zend_string *_interned_name = zend_new_interned_string(_name); 83 | 84 | #if PHP_VERSION_ID >= 70300 85 | return zend_register_class_alias_ex(ZSTR_VAL(_interned_name), ZSTR_LEN(_interned_name), ce, 1); 86 | #else 87 | return zend_register_class_alias_ex(ZSTR_VAL(_interned_name), ZSTR_LEN(_interned_name), ce); 88 | #endif 89 | } 90 | 91 | #define ROCKSDB_CLASS_ALIAS(name, module) do { \ 92 | if (name) { \ 93 | rocksdb_zend_register_class_alias(ZEND_STRL(name), module##_ce); \ 94 | } \ 95 | } while (0) 96 | 97 | #define ROCKSDB_CLASS_ALIAS_SHORT_NAME(shortName, module) do { \ 98 | ROCKSDB_CLASS_ALIAS(shortName, module); \ 99 | } while (0) 100 | 101 | #define ROCKSDB_SET_CLASS_SERIALIZABLE(module, _serialize, _unserialize) \ 102 | module##_ce->serialize = _serialize; \ 103 | module##_ce->unserialize = _unserialize 104 | 105 | #define rocksdb_zend_class_clone_deny NULL 106 | #define ROCKSDB_SET_CLASS_CLONEABLE(module, _clone_obj) \ 107 | module##_handlers.clone_obj = _clone_obj 108 | 109 | #define ROCKSDB_SET_CLASS_UNSET_PROPERTY_HANDLER(module, _unset_property) \ 110 | module##_handlers.unset_property = _unset_property 111 | 112 | #define ROCKSDB_INIT_CLASS_ENTRY_BASE(module, namespaceName, snake_name, shortName, methods, parent_ce) do { \ 113 | zend_class_entry _##module##_ce; \ 114 | INIT_CLASS_ENTRY(_##module##_ce, namespaceName, methods); \ 115 | module##_ce = zend_register_internal_class_ex(&_##module##_ce, parent_ce); \ 116 | ROCKSDB_CLASS_ALIAS(snake_name, module); \ 117 | ROCKSDB_CLASS_ALIAS_SHORT_NAME(shortName, module); \ 118 | } while (0) 119 | 120 | #define ROCKSDB_INIT_CLASS_ENTRY(module, namespaceName, snake_name, shortName, methods) \ 121 | ROCKSDB_INIT_CLASS_ENTRY_BASE(module, namespaceName, snake_name, shortName, methods, NULL); \ 122 | memcpy(&module##_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)) 123 | 124 | #define ROCKSDB_INIT_CLASS_ENTRY_EX(module, namespaceName, snake_name, shortName, methods, parent_module) \ 125 | ROCKSDB_INIT_CLASS_ENTRY_BASE(module, namespaceName, snake_name, shortName, methods, parent_module##_ce); \ 126 | memcpy(&module##_handlers, &parent_module##_handlers, sizeof(zend_object_handlers)) 127 | 128 | #define ROCKSDB_INIT_CLASS_ENTRY_EX2(module, namespaceName, snake_name, shortName, methods, parent_module_ce, parent_module_handlers) \ 129 | ROCKSDB_INIT_CLASS_ENTRY_BASE(module, namespaceName, snake_name, shortName, methods, parent_module_ce); \ 130 | memcpy(&module##_handlers, parent_module_handlers, sizeof(zend_object_handlers)) 131 | 132 | #if PHP_VERSION_ID < 80000 133 | static inline void rocksdb_zend_class_unset_property_deny(zval *zobject, zval *zmember, void **cache_slot) 134 | { 135 | zend_class_entry *ce = Z_OBJCE_P(zobject); 136 | while (ce->parent) 137 | { 138 | ce = ce->parent; 139 | } 140 | if (EXPECTED(zend_hash_find(&ce->properties_info, Z_STR_P(zmember)))) 141 | { 142 | zend_throw_error(NULL, "Property %s of class %s cannot be unset", Z_STRVAL_P(zmember), ROCKSDB_Z_OBJCE_NAME_VAL_P(zobject)); 143 | return; 144 | } 145 | std_object_handlers.unset_property(zobject, zmember, cache_slot); 146 | } 147 | #else 148 | static inline void rocksdb_zend_class_unset_property_deny(zend_object *object, zend_string *member, void **cache_slot) 149 | { 150 | zend_class_entry *ce = object->ce; 151 | while (ce->parent) 152 | { 153 | ce = ce->parent; 154 | } 155 | if (EXPECTED(zend_hash_find(&ce->properties_info, member))) 156 | { 157 | zend_throw_error(NULL, "Property %s of class %s cannot be unset", ZSTR_VAL(member), ZSTR_VAL(object->ce->name)); 158 | return; 159 | } 160 | std_object_handlers.unset_property(object, member, cache_slot); 161 | } 162 | #endif 163 | 164 | # if defined(ZTS) && defined(COMPILE_DL_ROCKSDB) 165 | ZEND_TSRMLS_CACHE_EXTERN() 166 | # endif 167 | 168 | #endif /* PHP_ROCKSDB_H */ 169 | -------------------------------------------------------------------------------- /rebuild.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | phpize --clean && phpize && ./configure && make && make install -------------------------------------------------------------------------------- /rocksdb_db.cc: -------------------------------------------------------------------------------- 1 | /* rocksdb extension for PHP */ 2 | 3 | #ifdef HAVE_CONFIG_H 4 | # include "config.h" 5 | #endif 6 | 7 | #include "php_rocksdb.h" 8 | 9 | #include "rocksdb/db.h" 10 | #include "rocksdb/merge_operator.h" 11 | 12 | #include "stringappend.h" 13 | #include "error.h" 14 | 15 | using namespace rocksdb; 16 | 17 | typedef struct 18 | { 19 | DB *db; 20 | zend_object std; 21 | } rocksdb_db_t; 22 | 23 | zend_class_entry *rocksdb_db_ce; 24 | static zend_object_handlers rocksdb_db_handlers; 25 | 26 | extern void php_rocksdb_iterator_set_ptr(zval *zobject, Iterator *iter); 27 | extern WriteBatch *php_rocksdb_write_batch_get_ptr(zval *zobject); 28 | extern void check_rocksdb_db_options(Options &op, HashTable *vht); 29 | extern void check_rocksdb_db_write_options(WriteOptions &wop, HashTable *vht); 30 | extern void check_rocksdb_db_read_options(ReadOptions &rop, HashTable *vht); 31 | 32 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_db_void, 0, 0, 0) 33 | ZEND_END_ARG_INFO() 34 | 35 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_db_open, 0, 0, 2) 36 | ZEND_ARG_INFO(0, dbName) 37 | ZEND_ARG_INFO(0, options) 38 | ZEND_END_ARG_INFO() 39 | 40 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_db_openForReadOnly, 0, 0, 2) 41 | ZEND_ARG_INFO(0, dbName) 42 | ZEND_ARG_INFO(0, options) 43 | ZEND_END_ARG_INFO() 44 | 45 | 46 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_db_openAsSecondary, 0, 0, 3) 47 | ZEND_ARG_INFO(0, dbName) 48 | ZEND_ARG_INFO(0, options) 49 | ZEND_ARG_INFO(0, secondaryPath) 50 | ZEND_END_ARG_INFO() 51 | 52 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_db_put, 0, 0, 3) 53 | ZEND_ARG_INFO(0, key) 54 | ZEND_ARG_INFO(0, value) 55 | ZEND_ARG_INFO(0, writeOptions) 56 | ZEND_END_ARG_INFO() 57 | 58 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_db_write, 0, 0, 2) 59 | ZEND_ARG_INFO(0, batch) 60 | ZEND_ARG_INFO(0, writeOptions) 61 | ZEND_END_ARG_INFO() 62 | 63 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_db_get, 0, 0, 2) 64 | ZEND_ARG_INFO(0, key) 65 | ZEND_ARG_INFO(0, readOptions) 66 | ZEND_END_ARG_INFO() 67 | 68 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_db_del, 0, 0, 2) 69 | ZEND_ARG_INFO(0, key) 70 | ZEND_ARG_INFO(0, writeOptions) 71 | ZEND_END_ARG_INFO() 72 | 73 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_db_deleteRange, 0, 0, 3) 74 | ZEND_ARG_INFO(0, beginKey) 75 | ZEND_ARG_INFO(0, endKey) 76 | ZEND_ARG_INFO(0, writeOptions) 77 | ZEND_END_ARG_INFO() 78 | 79 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_db_newIterator, 0, 0, 2) 80 | ZEND_ARG_INFO(0, beginKey) 81 | ZEND_ARG_INFO(0, readOptions) 82 | ZEND_END_ARG_INFO() 83 | 84 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_db_destroyDB, 0, 0, 2) 85 | ZEND_ARG_INFO(0, dbName) 86 | ZEND_ARG_INFO(0, options) 87 | ZEND_END_ARG_INFO() 88 | 89 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_db_keyMayExist, 0, 0, 2) 90 | ZEND_ARG_INFO(0, key) 91 | ZEND_ARG_INFO(0, readOptions) 92 | ZEND_END_ARG_INFO() 93 | 94 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_db_keyExist, 0, 0, 2) 95 | ZEND_ARG_INFO(0, key) 96 | ZEND_ARG_INFO(0, readOptions) 97 | ZEND_END_ARG_INFO() 98 | 99 | static inline rocksdb_db_t *php_rocksdb_db_fetch_object(zend_object *obj) 100 | { 101 | return (rocksdb_db_t *) ((char *) obj - rocksdb_db_handlers.offset); 102 | } 103 | 104 | static zend_object *php_rocksdb_db_create_object(zend_class_entry *ce) 105 | { 106 | rocksdb_db_t *rocksdb_db = (rocksdb_db_t *) zend_object_alloc(sizeof(rocksdb_db_t), ce); 107 | zend_object_std_init(&rocksdb_db->std, ce); 108 | object_properties_init(&rocksdb_db->std, ce); 109 | rocksdb_db->std.handlers = &rocksdb_db_handlers; 110 | return &rocksdb_db->std; 111 | } 112 | 113 | static void php_rocksdb_db_free_object(zend_object *object) 114 | { 115 | rocksdb_db_t *rocksdb_db = (rocksdb_db_t *) php_rocksdb_db_fetch_object(object); 116 | zend_object_std_dtor(&rocksdb_db->std); 117 | } 118 | 119 | static DB *php_rocksdb_db_get_ptr(zval *zobject) 120 | { 121 | return php_rocksdb_db_fetch_object(Z_OBJ_P(zobject))->db; 122 | } 123 | 124 | PHP_RINIT_FUNCTION(rocksdb) 125 | { 126 | return SUCCESS; 127 | } 128 | 129 | static PHP_METHOD(rocksdb, __construct) 130 | { 131 | } 132 | 133 | static PHP_METHOD(rocksdb, open) 134 | { 135 | char *path; 136 | size_t path_len; 137 | zval *zoptions = nullptr; 138 | 139 | ZEND_PARSE_PARAMETERS_START(1, 2) 140 | Z_PARAM_STRING(path, path_len) 141 | Z_PARAM_OPTIONAL 142 | Z_PARAM_ARRAY(zoptions) 143 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 144 | 145 | rocksdb_db_t *rocksdb_db = php_rocksdb_db_fetch_object(Z_OBJ_P(ZEND_THIS)); 146 | 147 | Options options; 148 | options.IncreaseParallelism(); 149 | options.OptimizeLevelStyleCompaction(); 150 | 151 | if (zoptions) 152 | { 153 | check_rocksdb_db_options(options, Z_ARRVAL_P(zoptions)); 154 | } 155 | 156 | Status s = DB::Open(options, path, &rocksdb_db->db); 157 | if (!s.ok()) 158 | { 159 | zend_throw_exception(rocksdb_exception_ce, s.ToString().c_str(), ROCKSDB_OPEN_ERROR); 160 | } 161 | 162 | RETURN_TRUE; 163 | } 164 | 165 | static PHP_METHOD(rocksdb, openForReadOnly) 166 | { 167 | char *path; 168 | size_t path_len; 169 | zval *zoptions = nullptr; 170 | 171 | ZEND_PARSE_PARAMETERS_START(1, 2) 172 | Z_PARAM_STRING(path, path_len) 173 | Z_PARAM_OPTIONAL 174 | Z_PARAM_ARRAY(zoptions) 175 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 176 | 177 | rocksdb_db_t *rocksdb_db = php_rocksdb_db_fetch_object(Z_OBJ_P(ZEND_THIS)); 178 | 179 | Options options; 180 | options.IncreaseParallelism(); 181 | options.OptimizeLevelStyleCompaction(); 182 | 183 | if (zoptions) 184 | { 185 | check_rocksdb_db_options(options, Z_ARRVAL_P(zoptions)); 186 | } 187 | 188 | Status s = DB::OpenForReadOnly(options, path, &rocksdb_db->db); 189 | if (!s.ok()) 190 | { 191 | zend_throw_exception(rocksdb_exception_ce, s.ToString().c_str(), ROCKSDB_OPEN_ERROR); 192 | } 193 | 194 | RETURN_TRUE; 195 | } 196 | 197 | static PHP_METHOD(rocksdb, openAsSecondary) 198 | { 199 | char *path; 200 | size_t path_len; 201 | zval *zoptions = nullptr; 202 | char *secondary_path; 203 | size_t secondary_path_len; 204 | 205 | ZEND_PARSE_PARAMETERS_START(1, 4) 206 | Z_PARAM_STRING(path, path_len) 207 | Z_PARAM_OPTIONAL 208 | Z_PARAM_ARRAY(zoptions) 209 | Z_PARAM_STRING(secondary_path, secondary_path_len) 210 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 211 | 212 | rocksdb_db_t *rocksdb_db = php_rocksdb_db_fetch_object(Z_OBJ_P(ZEND_THIS)); 213 | 214 | Options options; 215 | options.IncreaseParallelism(); 216 | options.OptimizeLevelStyleCompaction(); 217 | 218 | if (zoptions) 219 | { 220 | check_rocksdb_db_options(options, Z_ARRVAL_P(zoptions)); 221 | } 222 | 223 | Status s = DB::OpenAsSecondary(options, path, secondary_path, &rocksdb_db->db); 224 | if (!s.ok()) 225 | { 226 | zend_throw_exception(rocksdb_exception_ce, s.ToString().c_str(), ROCKSDB_OPEN_ERROR); 227 | } 228 | 229 | RETURN_TRUE; 230 | } 231 | 232 | static PHP_METHOD(rocksdb, put) 233 | { 234 | char *key; 235 | size_t key_len; 236 | char *value; 237 | size_t value_len; 238 | zval *zwriteoptions = nullptr; 239 | 240 | ZEND_PARSE_PARAMETERS_START(2, 3) 241 | Z_PARAM_STRING(key, key_len) 242 | Z_PARAM_STRING(value, value_len) 243 | Z_PARAM_OPTIONAL 244 | Z_PARAM_ARRAY(zwriteoptions) 245 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 246 | 247 | DB *db = php_rocksdb_db_get_ptr(ZEND_THIS); 248 | WriteOptions wop; 249 | 250 | if (zwriteoptions) 251 | { 252 | check_rocksdb_db_write_options(wop, Z_ARRVAL_P(zwriteoptions)); 253 | } 254 | 255 | Status s = db->Put(wop, std::string(key, key_len), std::string(value, value_len)); 256 | if (!s.ok()) { 257 | zend_throw_exception(rocksdb_exception_ce, s.ToString().c_str(), ROCKSDB_PUT_ERROR); 258 | } 259 | 260 | RETURN_TRUE; 261 | } 262 | 263 | static PHP_METHOD(rocksdb, write) 264 | { 265 | zval *zbatch; 266 | zval *zwriteoptions = nullptr; 267 | 268 | ZEND_PARSE_PARAMETERS_START(1, 2) 269 | Z_PARAM_OBJECT(zbatch) 270 | Z_PARAM_OPTIONAL 271 | Z_PARAM_ARRAY(zwriteoptions) 272 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 273 | 274 | DB *db = php_rocksdb_db_get_ptr(ZEND_THIS); 275 | WriteBatch *batch = php_rocksdb_write_batch_get_ptr(zbatch); 276 | WriteOptions wop; 277 | 278 | if (zwriteoptions) 279 | { 280 | check_rocksdb_db_write_options(wop, Z_ARRVAL_P(zwriteoptions)); 281 | } 282 | 283 | Status s = db->Write(wop, batch); 284 | if (!s.ok()) { 285 | zend_throw_exception(rocksdb_exception_ce, s.ToString().c_str(), ROCKSDB_WRITE_ERROR); 286 | } 287 | 288 | RETURN_TRUE; 289 | } 290 | 291 | static PHP_METHOD(rocksdb, get) 292 | { 293 | char *key; 294 | size_t key_len; 295 | zval *zreadoptions = nullptr; 296 | 297 | ZEND_PARSE_PARAMETERS_START(1, 2) 298 | Z_PARAM_STRING(key, key_len) 299 | Z_PARAM_OPTIONAL 300 | Z_PARAM_ARRAY(zreadoptions) 301 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 302 | 303 | DB *db = php_rocksdb_db_get_ptr(ZEND_THIS); 304 | ReadOptions rop; 305 | 306 | if (zreadoptions) 307 | { 308 | check_rocksdb_db_read_options(rop, Z_ARRVAL_P(zreadoptions)); 309 | } 310 | 311 | std::string value; 312 | Status s = db->Get(rop, std::string(key, key_len), &value); 313 | if (!s.ok()) 314 | { 315 | zend_throw_exception(rocksdb_exception_ce, s.ToString().c_str(), ROCKSDB_GET_ERROR); 316 | } 317 | 318 | RETURN_STRINGL(value.c_str(), value.length()); 319 | } 320 | 321 | static PHP_METHOD(rocksdb, del) 322 | { 323 | char *key; 324 | size_t key_len; 325 | zval *zwriteoptions = nullptr; 326 | 327 | ZEND_PARSE_PARAMETERS_START(1, 2) 328 | Z_PARAM_STRING(key, key_len) 329 | Z_PARAM_OPTIONAL 330 | Z_PARAM_ARRAY(zwriteoptions) 331 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 332 | 333 | DB *db = php_rocksdb_db_get_ptr(ZEND_THIS); 334 | WriteOptions wop; 335 | 336 | if (zwriteoptions) 337 | { 338 | check_rocksdb_db_write_options(wop, Z_ARRVAL_P(zwriteoptions)); 339 | } 340 | 341 | Status s = db->Delete(wop, std::string(key, key_len)); 342 | if (!s.ok()) 343 | { 344 | zend_throw_exception(rocksdb_exception_ce, s.ToString().c_str(), ROCKSDB_DELETE_ERROR); 345 | } 346 | 347 | RETURN_TRUE; 348 | } 349 | 350 | static PHP_METHOD(rocksdb, deleteRange) 351 | { 352 | char *begin_key; 353 | size_t begin_key_len; 354 | char *end_key; 355 | size_t end_key_len; 356 | zval *zwriteoptions = nullptr; 357 | 358 | ZEND_PARSE_PARAMETERS_START(2, 3) 359 | Z_PARAM_STRING(begin_key, begin_key_len) 360 | Z_PARAM_STRING(end_key, end_key_len) 361 | Z_PARAM_OPTIONAL 362 | Z_PARAM_ARRAY(zwriteoptions) 363 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 364 | 365 | DB *db = php_rocksdb_db_get_ptr(ZEND_THIS); 366 | WriteOptions wop; 367 | 368 | if (zwriteoptions) 369 | { 370 | check_rocksdb_db_write_options(wop, Z_ARRVAL_P(zwriteoptions)); 371 | } 372 | 373 | Status s = db->DeleteRange(wop, 0, std::string(begin_key, begin_key_len), std::string(end_key, end_key_len)); 374 | if (!s.ok()) 375 | { 376 | zend_throw_exception(rocksdb_exception_ce, s.ToString().c_str(), ROCKSDB_DELETE_RANGE_ERROR); 377 | } 378 | 379 | RETURN_TRUE; 380 | } 381 | 382 | static PHP_METHOD(rocksdb, newIterator) 383 | { 384 | zval *begin_key; 385 | zval *zreadoptions = nullptr; 386 | 387 | ZEND_PARSE_PARAMETERS_START(1, 2) 388 | Z_PARAM_ZVAL(begin_key) 389 | Z_PARAM_OPTIONAL 390 | Z_PARAM_ARRAY(zreadoptions) 391 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 392 | 393 | DB *db = php_rocksdb_db_get_ptr(ZEND_THIS); 394 | ReadOptions rop; 395 | 396 | if (zreadoptions) 397 | { 398 | check_rocksdb_db_read_options(rop, Z_ARRVAL_P(zreadoptions)); 399 | } 400 | 401 | zval ziter; 402 | object_init_ex(&ziter, rocksdb_iterator_ce); 403 | Iterator *iter = db->NewIterator(rop); 404 | php_rocksdb_iterator_set_ptr(&ziter, iter); 405 | 406 | zend_call_method_with_1_params( 407 | &ziter, 408 | rocksdb_iterator_ce, 409 | &rocksdb_iterator_ce->constructor, 410 | (const char *) "__construct", 411 | NULL, 412 | begin_key 413 | ); 414 | 415 | RETVAL_OBJ(Z_OBJ_P(&ziter)); 416 | } 417 | 418 | static PHP_METHOD(rocksdb, close) 419 | { 420 | DB *db = php_rocksdb_db_get_ptr(ZEND_THIS); 421 | Status s = db->Close(); 422 | 423 | if (!s.ok()) 424 | { 425 | zend_throw_exception(rocksdb_exception_ce, s.ToString().c_str(), ROCKSDB_CLOSE_ERROR); 426 | } 427 | RETURN_TRUE; 428 | } 429 | 430 | static PHP_METHOD(rocksdb, destroyDB) 431 | { 432 | char *path; 433 | size_t path_len; 434 | zval *zoptions = nullptr; 435 | 436 | ZEND_PARSE_PARAMETERS_START(1, 2) 437 | Z_PARAM_STRING(path, path_len) 438 | Z_PARAM_OPTIONAL 439 | Z_PARAM_ARRAY(zoptions) 440 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 441 | 442 | Options options; 443 | if (zoptions) 444 | { 445 | check_rocksdb_db_options(options, Z_ARRVAL_P(zoptions)); 446 | } 447 | 448 | Status s = DestroyDB(path, options); 449 | if (!s.ok()) 450 | { 451 | zend_throw_exception(rocksdb_exception_ce, s.ToString().c_str(), ROCKSDB_DESTROY_ERROR); 452 | } 453 | RETURN_TRUE; 454 | } 455 | 456 | static PHP_METHOD(rocksdb, keyMayExist) 457 | { 458 | char *key; 459 | size_t key_len; 460 | zval *zreadoptions = nullptr; 461 | 462 | ZEND_PARSE_PARAMETERS_START(1, 2) 463 | Z_PARAM_STRING(key, key_len) 464 | Z_PARAM_OPTIONAL 465 | Z_PARAM_ARRAY(zreadoptions) 466 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 467 | 468 | DB *db = php_rocksdb_db_get_ptr(ZEND_THIS); 469 | ReadOptions rop; 470 | 471 | if (zreadoptions) 472 | { 473 | check_rocksdb_db_read_options(rop, Z_ARRVAL_P(zreadoptions)); 474 | } 475 | 476 | std::string value; 477 | bool isExist = db->KeyMayExist(rop, std::move(std::string(key, key_len)), &value); 478 | 479 | RETVAL_BOOL(isExist); 480 | } 481 | 482 | static PHP_METHOD(rocksdb, keyExist) 483 | { 484 | char *key; 485 | size_t key_len; 486 | zval *zreadoptions = nullptr; 487 | 488 | ZEND_PARSE_PARAMETERS_START(1, 2) 489 | Z_PARAM_STRING(key, key_len) 490 | Z_PARAM_OPTIONAL 491 | Z_PARAM_ARRAY(zreadoptions) 492 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 493 | 494 | DB *db = php_rocksdb_db_get_ptr(ZEND_THIS); 495 | ReadOptions rop; 496 | 497 | if (zreadoptions) 498 | { 499 | check_rocksdb_db_read_options(rop, Z_ARRVAL_P(zreadoptions)); 500 | } 501 | 502 | std::string value; 503 | Status s = db->Get(rop, std::string(key, key_len), &value); 504 | 505 | RETVAL_BOOL(!s.IsNotFound()); 506 | } 507 | 508 | static const zend_function_entry rocksdb_methods[] = 509 | { 510 | PHP_ME(rocksdb, __construct, arginfo_rocksdb_db_void, ZEND_ACC_PUBLIC) 511 | PHP_ME(rocksdb, open, arginfo_rocksdb_db_open, ZEND_ACC_PUBLIC) 512 | PHP_ME(rocksdb, openForReadOnly, arginfo_rocksdb_db_openForReadOnly, ZEND_ACC_PUBLIC) 513 | PHP_ME(rocksdb, openAsSecondary, arginfo_rocksdb_db_openAsSecondary, ZEND_ACC_PUBLIC) 514 | PHP_ME(rocksdb, put, arginfo_rocksdb_db_put, ZEND_ACC_PUBLIC) 515 | PHP_ME(rocksdb, write, arginfo_rocksdb_db_write, ZEND_ACC_PUBLIC) 516 | PHP_ME(rocksdb, get, arginfo_rocksdb_db_get, ZEND_ACC_PUBLIC) 517 | PHP_ME(rocksdb, del, arginfo_rocksdb_db_del, ZEND_ACC_PUBLIC) 518 | PHP_ME(rocksdb, deleteRange, arginfo_rocksdb_db_deleteRange, ZEND_ACC_PUBLIC) 519 | PHP_ME(rocksdb, newIterator, arginfo_rocksdb_db_newIterator, ZEND_ACC_PUBLIC) 520 | PHP_ME(rocksdb, close, arginfo_rocksdb_db_void, ZEND_ACC_PUBLIC) 521 | PHP_ME(rocksdb, destroyDB, arginfo_rocksdb_db_destroyDB, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC) 522 | PHP_ME(rocksdb, keyMayExist, arginfo_rocksdb_db_keyMayExist, ZEND_ACC_PUBLIC) 523 | PHP_ME(rocksdb, keyExist, arginfo_rocksdb_db_keyExist, ZEND_ACC_PUBLIC) 524 | PHP_FE_END 525 | }; 526 | 527 | PHP_MINIT_FUNCTION(rocksdb) 528 | { 529 | ROCKSDB_INIT_CLASS_ENTRY(rocksdb_db, "RocksDB\\DB", NULL, NULL, rocksdb_methods); 530 | ROCKSDB_SET_CLASS_CUSTOM_OBJECT(rocksdb_db, php_rocksdb_db_create_object, php_rocksdb_db_free_object, rocksdb_db_t, std); 531 | 532 | php_rocksdb_exception_minit(module_number); 533 | php_rocksdb_iterator_minit(module_number); 534 | php_rocksdb_write_batch_minit(module_number); 535 | php_rocksdb_transaction_db_minit(module_number); 536 | php_rocksdb_transaction_minit(module_number); 537 | php_rocksdb_snapshot_minit(module_number); 538 | 539 | return SUCCESS; 540 | } 541 | 542 | PHP_MINFO_FUNCTION(rocksdb) 543 | { 544 | char buf[64]; 545 | 546 | php_info_print_table_start(); 547 | php_info_print_table_header(2, "RocksDB support", "enabled"); 548 | php_info_print_table_row(2, "Author", "Codinghuang "); 549 | php_info_print_table_row(2, "Version", PHP_ROCKSDB_VERSION); 550 | snprintf(buf, sizeof(buf), "%s %s", __DATE__, __TIME__); 551 | php_info_print_table_row(2, "Built", buf); 552 | php_info_print_table_end(); 553 | DISPLAY_INI_ENTRIES(); 554 | } 555 | 556 | static const zend_function_entry rocksdb_functions[] = { 557 | PHP_FE_END 558 | }; 559 | 560 | zend_module_entry rocksdb_module_entry = { 561 | STANDARD_MODULE_HEADER, 562 | "rocksdb", /* Extension name */ 563 | rocksdb_functions, /* zend_function_entry */ 564 | PHP_MINIT(rocksdb), /* PHP_MINIT - Module initialization */ 565 | NULL, /* PHP_MSHUTDOWN - Module shutdown */ 566 | PHP_RINIT(rocksdb), /* PHP_RINIT - Request initialization */ 567 | NULL, /* PHP_RSHUTDOWN - Request shutdown */ 568 | PHP_MINFO(rocksdb), /* PHP_MINFO - Module info */ 569 | PHP_ROCKSDB_VERSION, /* Version */ 570 | STANDARD_MODULE_PROPERTIES 571 | }; 572 | 573 | #ifdef COMPILE_DL_ROCKSDB 574 | # ifdef ZTS 575 | ZEND_TSRMLS_CACHE_DEFINE() 576 | # endif 577 | ZEND_GET_MODULE(rocksdb) 578 | #endif 579 | 580 | -------------------------------------------------------------------------------- /rocksdb_exception.cc: -------------------------------------------------------------------------------- 1 | #include "php_rocksdb.h" 2 | 3 | zend_class_entry *rocksdb_exception_ce; 4 | zend_object_handlers rocksdb_exception_handlers; 5 | 6 | void php_rocksdb_exception_minit(int module_number) 7 | { 8 | ROCKSDB_INIT_CLASS_ENTRY_EX2(rocksdb_exception, "RocksDB\\Exception", NULL, NULL, NULL, zend_ce_exception, zend_get_std_object_handlers()); 9 | } -------------------------------------------------------------------------------- /rocksdb_iterator.cc: -------------------------------------------------------------------------------- 1 | #include "php_rocksdb.h" 2 | #include "rocksdb/db.h" 3 | #include 4 | 5 | using namespace rocksdb; 6 | 7 | typedef struct 8 | { 9 | Iterator *iterator; 10 | zend_object std; 11 | } rocksdb_iterator_t; 12 | 13 | zend_class_entry *rocksdb_iterator_ce; 14 | zend_object_handlers rocksdb_iterator_handlers; 15 | 16 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_iterator_void, 0, 0, 0) 17 | ZEND_END_ARG_INFO() 18 | 19 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_iterator__construct, 0, 0, 1) 20 | ZEND_ARG_INFO(0, begin_key) 21 | ZEND_END_ARG_INFO() 22 | 23 | static PHP_METHOD(rocksdb_iterator, __construct); 24 | static PHP_METHOD(rocksdb_iterator, __destruct); 25 | static PHP_METHOD(rocksdb_iterator, rewind); 26 | static PHP_METHOD(rocksdb_iterator, next); 27 | static PHP_METHOD(rocksdb_iterator, current); 28 | static PHP_METHOD(rocksdb_iterator, key); 29 | static PHP_METHOD(rocksdb_iterator, valid); 30 | static PHP_METHOD(rocksdb_iterator, count); 31 | 32 | static inline rocksdb_iterator_t* php_rocksdb_iterator_fetch_object(zend_object *obj) 33 | { 34 | return (rocksdb_iterator_t *) ((char *) obj - rocksdb_iterator_handlers.offset); 35 | } 36 | 37 | Iterator* php_rocksdb_iterator_get_ptr(zval *zobject) 38 | { 39 | return php_rocksdb_iterator_fetch_object(Z_OBJ_P(zobject))->iterator; 40 | } 41 | 42 | void php_rocksdb_iterator_set_ptr(zval *zobject, Iterator *iter) 43 | { 44 | php_rocksdb_iterator_fetch_object(Z_OBJ_P(zobject))->iterator = iter; 45 | } 46 | 47 | static void php_rocksdb_iterator_free_object(zend_object *object) 48 | { 49 | delete php_rocksdb_iterator_fetch_object(object)->iterator; 50 | zend_object_std_dtor(object); 51 | } 52 | 53 | static zend_object *php_rocksdb_iterator_create_object(zend_class_entry *ce) 54 | { 55 | rocksdb_iterator_t *iter = (rocksdb_iterator_t *) zend_object_alloc(sizeof(rocksdb_iterator_t), ce); 56 | zend_object_std_init(&iter->std, ce); 57 | object_properties_init(&iter->std, ce); 58 | iter->std.handlers = &rocksdb_iterator_handlers; 59 | return &iter->std; 60 | } 61 | 62 | static PHP_METHOD(rocksdb_iterator, __construct) 63 | { 64 | char *begin_key; 65 | size_t begin_key_len; 66 | 67 | ZEND_PARSE_PARAMETERS_START(1, 1) 68 | Z_PARAM_STRING(begin_key, begin_key_len) 69 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 70 | 71 | Iterator *iter = php_rocksdb_iterator_get_ptr(ZEND_THIS); 72 | iter->Seek(std::string(begin_key, begin_key_len)); 73 | } 74 | 75 | static PHP_METHOD(rocksdb_iterator, __destruct) 76 | { 77 | } 78 | 79 | static PHP_METHOD(rocksdb_iterator, rewind) 80 | { 81 | Iterator *iter = php_rocksdb_iterator_get_ptr(ZEND_THIS); 82 | iter->Reset(); 83 | } 84 | 85 | static PHP_METHOD(rocksdb_iterator, next) 86 | { 87 | Iterator *iter = php_rocksdb_iterator_get_ptr(ZEND_THIS); 88 | iter->Next(); 89 | } 90 | 91 | static PHP_METHOD(rocksdb_iterator, current) 92 | { 93 | Iterator *iter = php_rocksdb_iterator_get_ptr(ZEND_THIS); 94 | std::string value = iter->value().ToString(); 95 | 96 | RETURN_STRINGL(value.c_str(), value.length()); 97 | } 98 | 99 | static PHP_METHOD(rocksdb_iterator, key) 100 | { 101 | Iterator *iter = php_rocksdb_iterator_get_ptr(ZEND_THIS); 102 | std::string key = iter->key().ToString(); 103 | 104 | RETURN_STRINGL(key.c_str(), key.length()); 105 | } 106 | 107 | static PHP_METHOD(rocksdb_iterator, valid) 108 | { 109 | Iterator *iter = php_rocksdb_iterator_get_ptr(ZEND_THIS); 110 | 111 | RETURN_BOOL(iter->Valid()); 112 | } 113 | 114 | static PHP_METHOD(rocksdb_iterator, count) 115 | { 116 | php_error_docref(NULL, E_WARNING, "The count interface is not implemented"); 117 | } 118 | 119 | static const zend_function_entry rocksdb_iterator_methods[] = 120 | { 121 | PHP_ME(rocksdb_iterator, __construct, arginfo_rocksdb_iterator__construct, ZEND_ACC_PUBLIC) 122 | PHP_ME(rocksdb_iterator, __destruct, arginfo_rocksdb_iterator_void, ZEND_ACC_PUBLIC) 123 | PHP_ME(rocksdb_iterator, rewind, arginfo_rocksdb_iterator_void, ZEND_ACC_PUBLIC) 124 | PHP_ME(rocksdb_iterator, next, arginfo_rocksdb_iterator_void, ZEND_ACC_PUBLIC) 125 | PHP_ME(rocksdb_iterator, current, arginfo_rocksdb_iterator_void, ZEND_ACC_PUBLIC) 126 | PHP_ME(rocksdb_iterator, key, arginfo_rocksdb_iterator_void, ZEND_ACC_PUBLIC) 127 | PHP_ME(rocksdb_iterator, valid, arginfo_rocksdb_iterator_void, ZEND_ACC_PUBLIC) 128 | PHP_ME(rocksdb_iterator, count, arginfo_rocksdb_iterator_void, ZEND_ACC_PUBLIC) 129 | PHP_FE_END 130 | }; 131 | 132 | void php_rocksdb_iterator_minit(int module_number) 133 | { 134 | ROCKSDB_INIT_CLASS_ENTRY(rocksdb_iterator, "RocksDB\\Iterator", NULL, NULL, rocksdb_iterator_methods); 135 | ROCKSDB_SET_CLASS_SERIALIZABLE(rocksdb_iterator, zend_class_serialize_deny, zend_class_unserialize_deny); 136 | ROCKSDB_SET_CLASS_CLONEABLE(rocksdb_iterator, rocksdb_zend_class_clone_deny); 137 | ROCKSDB_SET_CLASS_UNSET_PROPERTY_HANDLER(rocksdb_iterator, rocksdb_zend_class_unset_property_deny); 138 | ROCKSDB_SET_CLASS_CUSTOM_OBJECT(rocksdb_iterator, php_rocksdb_iterator_create_object, php_rocksdb_iterator_free_object, rocksdb_iterator_t, std); 139 | zend_class_implements(rocksdb_iterator_ce, 1, zend_ce_iterator); 140 | } -------------------------------------------------------------------------------- /rocksdb_options.cc: -------------------------------------------------------------------------------- 1 | #include "php_rocksdb.h" 2 | 3 | #include "rocksdb/db.h" 4 | #include "rocksdb/utilities/transaction.h" 5 | #include "rocksdb/utilities/transaction_db.h" 6 | #include "rocksdb/merge_operator.h" 7 | 8 | #include "stringappend.h" 9 | 10 | using namespace rocksdb; 11 | 12 | extern Snapshot *php_rocksdb_snapshot_get_ptr(zval *zobject); 13 | 14 | void check_rocksdb_db_options(Options &op, HashTable *vht) 15 | { 16 | zval *ztmp; 17 | 18 | if (php_rocksdb_array_get_value(vht, "create_if_missing", ztmp)) 19 | { 20 | op.create_if_missing = zval_is_true(ztmp); 21 | } 22 | if (php_rocksdb_array_get_value(vht, "error_if_exists", ztmp)) 23 | { 24 | op.error_if_exists = zval_is_true(ztmp); 25 | } 26 | if (php_rocksdb_array_get_value(vht, "paranoid_checks", ztmp)) 27 | { 28 | op.paranoid_checks = zval_is_true(ztmp); 29 | } 30 | if (php_rocksdb_array_get_value(vht, "max_open_files", ztmp)) 31 | { 32 | op.max_open_files = zval_get_long(ztmp); 33 | } 34 | if (php_rocksdb_array_get_value(vht, "merge_operator", ztmp)) 35 | { 36 | char *delim_char = ZSTR_VAL(zval_get_string(ztmp)); 37 | op.merge_operator.reset(new StringAppendOperator(delim_char[0])); 38 | } 39 | } 40 | 41 | void check_rocksdb_db_write_options(WriteOptions &wop, HashTable *vht) 42 | { 43 | zval *ztmp; 44 | 45 | if (php_rocksdb_array_get_value(vht, "disableWAL", ztmp)) 46 | { 47 | wop.disableWAL = zval_is_true(ztmp); 48 | } 49 | if (php_rocksdb_array_get_value(vht, "ignore_missing_column_families", ztmp)) 50 | { 51 | wop.ignore_missing_column_families = zval_is_true(ztmp); 52 | } 53 | if (php_rocksdb_array_get_value(vht, "low_pri", ztmp)) 54 | { 55 | wop.low_pri = zval_is_true(ztmp); 56 | } 57 | if (php_rocksdb_array_get_value(vht, "no_slowdown", ztmp)) 58 | { 59 | wop.no_slowdown = zval_is_true(ztmp); 60 | } 61 | if (php_rocksdb_array_get_value(vht, "sync", ztmp)) 62 | { 63 | wop.sync = zval_is_true(ztmp); 64 | } 65 | } 66 | 67 | void check_rocksdb_transaction_db_options(TransactionDBOptions &txn_db_options, HashTable *vht) 68 | { 69 | zval *ztmp; 70 | 71 | if (php_rocksdb_array_get_value(vht, "default_lock_timeout", ztmp)) 72 | { 73 | txn_db_options.default_lock_timeout = zval_get_long(ztmp); 74 | } 75 | if (php_rocksdb_array_get_value(vht, "max_num_deadlocks", ztmp)) 76 | { 77 | txn_db_options.max_num_deadlocks = zval_get_long(ztmp); 78 | } 79 | if (php_rocksdb_array_get_value(vht, "max_num_locks", ztmp)) 80 | { 81 | txn_db_options.max_num_locks = zval_get_long(ztmp); 82 | } 83 | if (php_rocksdb_array_get_value(vht, "num_stripes", ztmp)) 84 | { 85 | txn_db_options.num_stripes = zval_get_long(ztmp); 86 | } 87 | if (php_rocksdb_array_get_value(vht, "rollback_merge_operands", ztmp)) 88 | { 89 | txn_db_options.rollback_merge_operands = zval_is_true(ztmp); 90 | } 91 | if (php_rocksdb_array_get_value(vht, "transaction_lock_timeout", ztmp)) 92 | { 93 | txn_db_options.transaction_lock_timeout = zval_get_long(ztmp); 94 | } 95 | } 96 | 97 | void check_rocksdb_transaction_options(TransactionOptions &txn_options, HashTable *vht) 98 | { 99 | zval *ztmp; 100 | 101 | if (php_rocksdb_array_get_value(vht, "deadlock_detect", ztmp)) 102 | { 103 | txn_options.deadlock_detect = zval_is_true(ztmp); 104 | } 105 | if (php_rocksdb_array_get_value(vht, "deadlock_detect_depth", ztmp)) 106 | { 107 | txn_options.deadlock_detect_depth = zval_get_long(ztmp); 108 | } 109 | if (php_rocksdb_array_get_value(vht, "expiration", ztmp)) 110 | { 111 | txn_options.expiration = zval_get_long(ztmp); 112 | } 113 | if (php_rocksdb_array_get_value(vht, "lock_timeout", ztmp)) 114 | { 115 | txn_options.lock_timeout = zval_get_long(ztmp); 116 | } 117 | if (php_rocksdb_array_get_value(vht, "max_write_batch_size", ztmp)) 118 | { 119 | txn_options.max_write_batch_size = zval_get_long(ztmp); 120 | } 121 | if (php_rocksdb_array_get_value(vht, "set_snapshot", ztmp)) 122 | { 123 | txn_options.set_snapshot = zval_is_true(ztmp); 124 | } 125 | if (php_rocksdb_array_get_value(vht, "skip_concurrency_control", ztmp)) 126 | { 127 | txn_options.skip_concurrency_control = zval_is_true(ztmp); 128 | } 129 | if (php_rocksdb_array_get_value(vht, "use_only_the_last_commit_time_batch_for_recovery", ztmp)) 130 | { 131 | txn_options.use_only_the_last_commit_time_batch_for_recovery = zval_is_true(ztmp); 132 | } 133 | } 134 | 135 | void check_rocksdb_db_read_options(ReadOptions &rop, HashTable *vht) 136 | { 137 | zval *ztmp; 138 | 139 | if (php_rocksdb_array_get_value(vht, "background_purge_on_iterator_cleanup", ztmp)) 140 | { 141 | rop.background_purge_on_iterator_cleanup = zval_is_true(ztmp); 142 | } 143 | if (php_rocksdb_array_get_value(vht, "fill_cache", ztmp)) 144 | { 145 | rop.fill_cache = zval_is_true(ztmp); 146 | } 147 | if (php_rocksdb_array_get_value(vht, "ignore_range_deletions", ztmp)) 148 | { 149 | rop.ignore_range_deletions = zval_is_true(ztmp); 150 | } 151 | if (php_rocksdb_array_get_value(vht, "managed", ztmp)) 152 | { 153 | rop.managed = zval_is_true(ztmp); 154 | } 155 | if (php_rocksdb_array_get_value(vht, "pin_data", ztmp)) 156 | { 157 | rop.pin_data = zval_is_true(ztmp); 158 | } 159 | if (php_rocksdb_array_get_value(vht, "prefix_same_as_start", ztmp)) 160 | { 161 | rop.prefix_same_as_start = zval_is_true(ztmp); 162 | } 163 | if (php_rocksdb_array_get_value(vht, "snapshot", ztmp)) 164 | { 165 | rop.snapshot = php_rocksdb_snapshot_get_ptr(ztmp); 166 | } 167 | if (php_rocksdb_array_get_value(vht, "tailing", ztmp)) 168 | { 169 | rop.tailing = zval_is_true(ztmp); 170 | } 171 | if (php_rocksdb_array_get_value(vht, "total_order_seek", ztmp)) 172 | { 173 | rop.total_order_seek = zval_is_true(ztmp); 174 | } 175 | if (php_rocksdb_array_get_value(vht, "verify_checksums", ztmp)) 176 | { 177 | rop.verify_checksums = zval_is_true(ztmp); 178 | } 179 | } -------------------------------------------------------------------------------- /rocksdb_snapshot.cc: -------------------------------------------------------------------------------- 1 | /* rocksdb extension for PHP */ 2 | 3 | #ifdef HAVE_CONFIG_H 4 | # include "config.h" 5 | #endif 6 | 7 | #include "php_rocksdb.h" 8 | 9 | #include "rocksdb/db.h" 10 | 11 | #include "error.h" 12 | 13 | using namespace rocksdb; 14 | 15 | typedef struct 16 | { 17 | Snapshot *snapshot; 18 | zend_object std; 19 | } rocksdb_snapshot_t; 20 | 21 | zend_class_entry *rocksdb_snapshot_ce; 22 | static zend_object_handlers rocksdb_snapshot_handlers; 23 | 24 | static inline rocksdb_snapshot_t *php_rocksdb_snapshot_fetch_object(zend_object *obj) 25 | { 26 | return (rocksdb_snapshot_t *) ((char *) obj - rocksdb_snapshot_handlers.offset); 27 | } 28 | 29 | static zend_object *php_rocksdb_snapshot_create_object(zend_class_entry *ce) 30 | { 31 | rocksdb_snapshot_t *rocksdb_snapshot = (rocksdb_snapshot_t *) zend_object_alloc(sizeof(rocksdb_snapshot_t), ce); 32 | zend_object_std_init(&rocksdb_snapshot->std, ce); 33 | object_properties_init(&rocksdb_snapshot->std, ce); 34 | rocksdb_snapshot->std.handlers = &rocksdb_snapshot_handlers; 35 | return &rocksdb_snapshot->std; 36 | } 37 | 38 | static void php_rocksdb_snapshot_free_object(zend_object *object) 39 | { 40 | rocksdb_snapshot_t *rocksdb_snapshot = (rocksdb_snapshot_t *) php_rocksdb_snapshot_fetch_object(object); 41 | zend_object_std_dtor(&rocksdb_snapshot->std); 42 | } 43 | 44 | Snapshot *php_rocksdb_snapshot_get_ptr(zval *zobject) 45 | { 46 | return php_rocksdb_snapshot_fetch_object(Z_OBJ_P(zobject))->snapshot; 47 | } 48 | 49 | void php_rocksdb_snapshot_set_ptr(zval *zobject, const Snapshot *snapshot) 50 | { 51 | php_rocksdb_snapshot_fetch_object(Z_OBJ_P(zobject))->snapshot = (Snapshot *) snapshot; 52 | } 53 | 54 | static const zend_function_entry rocksdb_snapshot_methods[] = 55 | { 56 | PHP_FE_END 57 | }; 58 | 59 | void php_rocksdb_snapshot_minit(int module_number) 60 | { 61 | ROCKSDB_INIT_CLASS_ENTRY(rocksdb_snapshot, "RocksDB\\Snapshot", NULL, NULL, rocksdb_snapshot_methods); 62 | ROCKSDB_SET_CLASS_CUSTOM_OBJECT(rocksdb_snapshot, php_rocksdb_snapshot_create_object, php_rocksdb_snapshot_free_object, rocksdb_snapshot_t, std); 63 | } -------------------------------------------------------------------------------- /rocksdb_transaction.cc: -------------------------------------------------------------------------------- 1 | /* rocksdb extension for PHP */ 2 | 3 | #ifdef HAVE_CONFIG_H 4 | # include "config.h" 5 | #endif 6 | 7 | #include "php_rocksdb.h" 8 | 9 | #include "rocksdb/db.h" 10 | #include "rocksdb/options.h" 11 | #include "rocksdb/slice.h" 12 | #include "rocksdb/utilities/transaction.h" 13 | #include "rocksdb/utilities/transaction_db.h" 14 | 15 | #include "error.h" 16 | 17 | using namespace rocksdb; 18 | 19 | typedef struct 20 | { 21 | Transaction *db; 22 | zend_object std; 23 | } rocksdb_transaction_t; 24 | 25 | zend_class_entry *rocksdb_transaction_ce; 26 | static zend_object_handlers rocksdb_transaction_handlers; 27 | 28 | extern zend_class_entry *rocksdb_snapshot_ce; 29 | 30 | extern void check_rocksdb_db_read_options(ReadOptions &rop, HashTable *vht); 31 | 32 | void php_rocksdb_snapshot_set_ptr(zval *zobject, const Snapshot *snapshot); 33 | 34 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_transaction_void, 0, 0, 0) 35 | ZEND_END_ARG_INFO() 36 | 37 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_transaction_put, 0, 0, 2) 38 | ZEND_ARG_INFO(0, key) 39 | ZEND_ARG_INFO(0, value) 40 | ZEND_END_ARG_INFO() 41 | 42 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_transaction_get, 0, 0, 2) 43 | ZEND_ARG_INFO(0, key) 44 | ZEND_ARG_INFO(0, readOptions) 45 | ZEND_END_ARG_INFO() 46 | 47 | static inline rocksdb_transaction_t *php_rocksdb_transaction_fetch_object(zend_object *obj) 48 | { 49 | return (rocksdb_transaction_t *) ((char *) obj - rocksdb_transaction_handlers.offset); 50 | } 51 | 52 | static zend_object *php_rocksdb_transaction_create_object(zend_class_entry *ce) 53 | { 54 | rocksdb_transaction_t *rocksdb_transaction = (rocksdb_transaction_t *) zend_object_alloc(sizeof(rocksdb_transaction_t), ce); 55 | zend_object_std_init(&rocksdb_transaction->std, ce); 56 | object_properties_init(&rocksdb_transaction->std, ce); 57 | rocksdb_transaction->std.handlers = &rocksdb_transaction_handlers; 58 | return &rocksdb_transaction->std; 59 | } 60 | 61 | static void php_rocksdb_transaction_free_object(zend_object *object) 62 | { 63 | rocksdb_transaction_t *rocksdb_transaction = (rocksdb_transaction_t *) php_rocksdb_transaction_fetch_object(object); 64 | zend_object_std_dtor(&rocksdb_transaction->std); 65 | } 66 | 67 | static Transaction *php_rocksdb_transaction_get_ptr(zval *zobject) 68 | { 69 | return php_rocksdb_transaction_fetch_object(Z_OBJ_P(zobject))->db; 70 | } 71 | 72 | void php_rocksdb_transaction_set_ptr(zval *zobject, Transaction *db) 73 | { 74 | php_rocksdb_transaction_fetch_object(Z_OBJ_P(zobject))->db = db; 75 | } 76 | 77 | static PHP_METHOD(rocksdb_transaction, put) 78 | { 79 | char *key; 80 | size_t key_len; 81 | char *value; 82 | size_t value_len; 83 | 84 | ZEND_PARSE_PARAMETERS_START(2, 2) 85 | Z_PARAM_STRING(key, key_len) 86 | Z_PARAM_STRING(value, value_len) 87 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 88 | 89 | Transaction *transaction = php_rocksdb_transaction_get_ptr(ZEND_THIS); 90 | 91 | Status s = transaction->Put(std::string(key, key_len), std::string(value, value_len)); 92 | if (!s.ok()) { 93 | zend_throw_exception(rocksdb_exception_ce, s.ToString().c_str(), ROCKSDB_PUT_ERROR); 94 | } 95 | 96 | RETURN_TRUE; 97 | } 98 | 99 | static PHP_METHOD(rocksdb_transaction, get) 100 | { 101 | char *key; 102 | size_t key_len; 103 | zval *zreadoptions = nullptr; 104 | 105 | ZEND_PARSE_PARAMETERS_START(1, 2) 106 | Z_PARAM_STRING(key, key_len) 107 | Z_PARAM_OPTIONAL 108 | Z_PARAM_ARRAY(zreadoptions) 109 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 110 | 111 | Transaction *transaction = php_rocksdb_transaction_get_ptr(ZEND_THIS); 112 | ReadOptions rop; 113 | 114 | if (zreadoptions) 115 | { 116 | check_rocksdb_db_read_options(rop, Z_ARRVAL_P(zreadoptions)); 117 | } 118 | 119 | std::string value; 120 | Status s = transaction->Get(rop, std::string(key, key_len), &value); 121 | if (!s.ok()) 122 | { 123 | zend_throw_exception(rocksdb_exception_ce, s.ToString().c_str(), ROCKSDB_GET_ERROR); 124 | } 125 | 126 | RETURN_STRINGL(value.c_str(), value.length()); 127 | } 128 | 129 | static PHP_METHOD(rocksdb_transaction, commit) 130 | { 131 | Transaction *transaction = php_rocksdb_transaction_get_ptr(ZEND_THIS); 132 | 133 | Status s = transaction->Commit(); 134 | if (!s.ok()) { 135 | zend_throw_exception(rocksdb_exception_ce, s.ToString().c_str(), ROCKSDB_COMMIT_ERROR); 136 | } 137 | 138 | RETURN_TRUE; 139 | } 140 | 141 | static PHP_METHOD(rocksdb_transaction, getSnapshot) 142 | { 143 | Transaction *transaction = php_rocksdb_transaction_get_ptr(ZEND_THIS); 144 | 145 | const Snapshot *snapshot = transaction->GetSnapshot(); 146 | 147 | zval zsnapshot; 148 | object_init_ex(&zsnapshot, rocksdb_snapshot_ce); 149 | php_rocksdb_snapshot_set_ptr(&zsnapshot, snapshot); 150 | 151 | RETVAL_OBJ(Z_OBJ_P(&zsnapshot)); 152 | } 153 | 154 | static PHP_METHOD(rocksdb_transaction, rollback) 155 | { 156 | Transaction *transaction = php_rocksdb_transaction_get_ptr(ZEND_THIS); 157 | 158 | Status s = transaction->Rollback(); 159 | if (!s.ok()) { 160 | zend_throw_exception(rocksdb_exception_ce, s.ToString().c_str(), ROCKSDB_COMMIT_ERROR); 161 | } 162 | 163 | RETURN_TRUE; 164 | } 165 | 166 | static PHP_METHOD(rocksdb_transaction, setSnapshot) 167 | { 168 | Transaction *transaction = php_rocksdb_transaction_get_ptr(ZEND_THIS); 169 | 170 | transaction->SetSnapshot(); 171 | 172 | RETURN_TRUE; 173 | } 174 | 175 | static PHP_METHOD(rocksdb_transaction, setSavePoint) 176 | { 177 | Transaction *transaction = php_rocksdb_transaction_get_ptr(ZEND_THIS); 178 | 179 | transaction->SetSavePoint(); 180 | 181 | RETURN_TRUE; 182 | } 183 | 184 | static const zend_function_entry rocksdb_transaction_methods[] = 185 | { 186 | PHP_ME(rocksdb_transaction, put, arginfo_rocksdb_transaction_put, ZEND_ACC_PUBLIC) 187 | PHP_ME(rocksdb_transaction, get, arginfo_rocksdb_transaction_get, ZEND_ACC_PUBLIC) 188 | PHP_ME(rocksdb_transaction, commit, arginfo_rocksdb_transaction_void, ZEND_ACC_PUBLIC) 189 | PHP_ME(rocksdb_transaction, getSnapshot, arginfo_rocksdb_transaction_void, ZEND_ACC_PUBLIC) 190 | PHP_ME(rocksdb_transaction, rollback, arginfo_rocksdb_transaction_void, ZEND_ACC_PUBLIC) 191 | PHP_ME(rocksdb_transaction, setSnapshot, arginfo_rocksdb_transaction_void, ZEND_ACC_PUBLIC) 192 | PHP_ME(rocksdb_transaction, setSavePoint, arginfo_rocksdb_transaction_void, ZEND_ACC_PUBLIC) 193 | PHP_FE_END 194 | }; 195 | 196 | void php_rocksdb_transaction_minit(int module_number) 197 | { 198 | ROCKSDB_INIT_CLASS_ENTRY(rocksdb_transaction, "RocksDB\\Transaction", NULL, NULL, rocksdb_transaction_methods); 199 | ROCKSDB_SET_CLASS_CUSTOM_OBJECT(rocksdb_transaction, php_rocksdb_transaction_create_object, php_rocksdb_transaction_free_object, rocksdb_transaction_t, std); 200 | } -------------------------------------------------------------------------------- /rocksdb_transaction_db.cc: -------------------------------------------------------------------------------- 1 | /* rocksdb extension for PHP */ 2 | 3 | #ifdef HAVE_CONFIG_H 4 | # include "config.h" 5 | #endif 6 | 7 | #include "php_rocksdb.h" 8 | 9 | #include "rocksdb/db.h" 10 | #include "rocksdb/options.h" 11 | #include "rocksdb/slice.h" 12 | #include "rocksdb/utilities/transaction.h" 13 | #include "rocksdb/utilities/transaction_db.h" 14 | 15 | #include "error.h" 16 | 17 | using namespace rocksdb; 18 | 19 | typedef struct 20 | { 21 | TransactionDB *db; 22 | zend_object std; 23 | } rocksdb_transaction_db_t; 24 | 25 | zend_class_entry *rocksdb_transaction_db_ce; 26 | static zend_object_handlers rocksdb_transaction_db_handlers; 27 | 28 | extern void php_rocksdb_transaction_set_ptr(zval *zobject, Transaction *db); 29 | 30 | extern void check_rocksdb_db_options(Options &op, HashTable *vht); 31 | extern void check_rocksdb_db_write_options(WriteOptions &wop, HashTable *vht); 32 | extern void check_rocksdb_db_read_options(ReadOptions &rop, HashTable *vht); 33 | extern void check_rocksdb_transaction_db_options(TransactionDBOptions &txn_db_options, HashTable *vht); 34 | extern void check_rocksdb_transaction_options(TransactionOptions &txn_options, HashTable *vht); 35 | 36 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_transaction_db_void, 0, 0, 0) 37 | ZEND_END_ARG_INFO() 38 | 39 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_transaction_db_open, 0, 0, 3) 40 | ZEND_ARG_INFO(0, dbName) 41 | ZEND_ARG_INFO(0, options) 42 | ZEND_ARG_INFO(0, txnDBOptions) 43 | ZEND_END_ARG_INFO() 44 | 45 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_transaction_db_beginTransaction, 0, 0, 2) 46 | ZEND_ARG_INFO(0, writeOptions) 47 | ZEND_ARG_INFO(0, txnOptions) 48 | ZEND_END_ARG_INFO() 49 | 50 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_transaction_db_put, 0, 0, 3) 51 | ZEND_ARG_INFO(0, key) 52 | ZEND_ARG_INFO(0, value) 53 | ZEND_ARG_INFO(0, writeOptions) 54 | ZEND_END_ARG_INFO() 55 | 56 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_transaction_db_get, 0, 0, 2) 57 | ZEND_ARG_INFO(0, key) 58 | ZEND_ARG_INFO(0, readOptions) 59 | ZEND_END_ARG_INFO() 60 | 61 | static inline rocksdb_transaction_db_t *php_rocksdb_transaction_db_fetch_object(zend_object *obj) 62 | { 63 | return (rocksdb_transaction_db_t *) ((char *) obj - rocksdb_transaction_db_handlers.offset); 64 | } 65 | 66 | static zend_object *php_rocksdb_transaction_db_create_object(zend_class_entry *ce) 67 | { 68 | rocksdb_transaction_db_t *rocksdb_transaction_db = (rocksdb_transaction_db_t *) zend_object_alloc(sizeof(rocksdb_transaction_db_t), ce); 69 | zend_object_std_init(&rocksdb_transaction_db->std, ce); 70 | object_properties_init(&rocksdb_transaction_db->std, ce); 71 | rocksdb_transaction_db->std.handlers = &rocksdb_transaction_db_handlers; 72 | return &rocksdb_transaction_db->std; 73 | } 74 | 75 | static void php_rocksdb_transaction_db_free_object(zend_object *object) 76 | { 77 | rocksdb_transaction_db_t *rocksdb_transaction_db = (rocksdb_transaction_db_t *) php_rocksdb_transaction_db_fetch_object(object); 78 | zend_object_std_dtor(&rocksdb_transaction_db->std); 79 | } 80 | 81 | static TransactionDB *php_rocksdb_transaction_db_get_ptr(zval *zobject) 82 | { 83 | return php_rocksdb_transaction_db_fetch_object(Z_OBJ_P(zobject))->db; 84 | } 85 | 86 | static PHP_METHOD(rocksdb_transaction_db, __construct) 87 | { 88 | 89 | } 90 | 91 | static PHP_METHOD(rocksdb_transaction_db, open) 92 | { 93 | char *path; 94 | size_t path_len; 95 | zval *zoptions = nullptr; 96 | zval *ztxn_db_options = nullptr; 97 | 98 | ZEND_PARSE_PARAMETERS_START(1, 3) 99 | Z_PARAM_STRING(path, path_len) 100 | Z_PARAM_OPTIONAL 101 | Z_PARAM_ARRAY(zoptions) 102 | Z_PARAM_ARRAY(ztxn_db_options) 103 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 104 | 105 | rocksdb_transaction_db_t *rocksdb_transaction_db = php_rocksdb_transaction_db_fetch_object(Z_OBJ_P(ZEND_THIS)); 106 | 107 | Options options; 108 | TransactionDBOptions txn_db_options; 109 | 110 | if (zoptions) 111 | { 112 | check_rocksdb_db_options(options, Z_ARRVAL_P(zoptions)); 113 | } 114 | if (ztxn_db_options) 115 | { 116 | check_rocksdb_transaction_db_options(txn_db_options, Z_ARRVAL_P(ztxn_db_options)); 117 | } 118 | 119 | Status s; 120 | 121 | s = TransactionDB::Open(options, txn_db_options, path, &rocksdb_transaction_db->db); 122 | 123 | if (!s.ok()) 124 | { 125 | zend_throw_exception(rocksdb_exception_ce, s.ToString().c_str(), ROCKSDB_OPEN_ERROR); 126 | } 127 | 128 | RETURN_TRUE; 129 | } 130 | 131 | static PHP_METHOD(rocksdb_transaction_db, beginTransaction) 132 | { 133 | zval *zwriteoptions = nullptr; 134 | zval *ztxn_options = nullptr; 135 | 136 | ZEND_PARSE_PARAMETERS_START(0, 2) 137 | Z_PARAM_OPTIONAL 138 | Z_PARAM_ARRAY(zwriteoptions) 139 | Z_PARAM_ARRAY(ztxn_options) 140 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 141 | 142 | TransactionDB *txn_db = php_rocksdb_transaction_db_get_ptr(ZEND_THIS); 143 | WriteOptions wop; 144 | TransactionOptions txn_options; 145 | 146 | if (zwriteoptions) 147 | { 148 | check_rocksdb_db_write_options(wop, Z_ARRVAL_P(zwriteoptions)); 149 | } 150 | if (ztxn_options) 151 | { 152 | check_rocksdb_transaction_options(txn_options, Z_ARRVAL_P(ztxn_options)); 153 | } 154 | 155 | Transaction *txn = txn_db->BeginTransaction(wop, txn_options); 156 | 157 | zval ztransaction; 158 | object_init_ex(&ztransaction, rocksdb_transaction_ce); 159 | php_rocksdb_transaction_set_ptr(&ztransaction, txn); 160 | 161 | RETVAL_OBJ(Z_OBJ_P(&ztransaction)); 162 | } 163 | 164 | static PHP_METHOD(rocksdb_transaction_db, put) 165 | { 166 | char *key; 167 | size_t key_len; 168 | char *value; 169 | size_t value_len; 170 | zval *zwriteoptions = nullptr; 171 | 172 | ZEND_PARSE_PARAMETERS_START(2, 3) 173 | Z_PARAM_STRING(key, key_len) 174 | Z_PARAM_STRING(value, value_len) 175 | Z_PARAM_OPTIONAL 176 | Z_PARAM_ARRAY(zwriteoptions) 177 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 178 | 179 | TransactionDB *db = php_rocksdb_transaction_db_get_ptr(ZEND_THIS); 180 | WriteOptions wop; 181 | 182 | if (zwriteoptions) 183 | { 184 | check_rocksdb_db_write_options(wop, Z_ARRVAL_P(zwriteoptions)); 185 | } 186 | 187 | Status s = db->Put(wop, std::string(key, key_len), std::string(value, value_len)); 188 | if (!s.ok()) { 189 | zend_throw_exception(rocksdb_exception_ce, s.ToString().c_str(), ROCKSDB_PUT_ERROR); 190 | } 191 | 192 | RETURN_TRUE; 193 | } 194 | 195 | static PHP_METHOD(rocksdb_transaction_db, get) 196 | { 197 | char *key; 198 | size_t key_len; 199 | zval *zreadoptions = nullptr; 200 | 201 | ZEND_PARSE_PARAMETERS_START(1, 2) 202 | Z_PARAM_STRING(key, key_len) 203 | Z_PARAM_OPTIONAL 204 | Z_PARAM_ARRAY(zreadoptions) 205 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 206 | 207 | TransactionDB *txn_db = php_rocksdb_transaction_db_get_ptr(ZEND_THIS); 208 | ReadOptions rop; 209 | 210 | if (zreadoptions) 211 | { 212 | check_rocksdb_db_read_options(rop, Z_ARRVAL_P(zreadoptions)); 213 | } 214 | 215 | std::string value; 216 | Status s = txn_db->Get(rop, std::string(key, key_len), &value); 217 | if (!s.ok()) 218 | { 219 | zend_throw_exception(rocksdb_exception_ce, s.ToString().c_str(), ROCKSDB_GET_ERROR); 220 | } 221 | 222 | RETURN_STRINGL(value.c_str(), value.length()); 223 | } 224 | 225 | static PHP_METHOD(rocksdb_transaction_db, close) 226 | { 227 | TransactionDB *txn_db = php_rocksdb_transaction_db_get_ptr(ZEND_THIS); 228 | Status s = txn_db->Close(); 229 | 230 | if (!s.ok()) 231 | { 232 | zend_throw_exception(rocksdb_exception_ce, s.ToString().c_str(), ROCKSDB_CLOSE_ERROR); 233 | } 234 | RETURN_TRUE; 235 | } 236 | 237 | static const zend_function_entry rocksdb_transaction_db_methods[] = 238 | { 239 | PHP_ME(rocksdb_transaction_db, __construct, arginfo_rocksdb_transaction_db_void, ZEND_ACC_PUBLIC) 240 | PHP_ME(rocksdb_transaction_db, open, arginfo_rocksdb_transaction_db_open, ZEND_ACC_PUBLIC) 241 | PHP_ME(rocksdb_transaction_db, beginTransaction, arginfo_rocksdb_transaction_db_beginTransaction, ZEND_ACC_PUBLIC) 242 | PHP_ME(rocksdb_transaction_db, put, arginfo_rocksdb_transaction_db_put, ZEND_ACC_PUBLIC) 243 | PHP_ME(rocksdb_transaction_db, get, arginfo_rocksdb_transaction_db_get, ZEND_ACC_PUBLIC) 244 | PHP_ME(rocksdb_transaction_db, close, arginfo_rocksdb_transaction_db_void, ZEND_ACC_PUBLIC) 245 | PHP_FE_END 246 | }; 247 | 248 | void php_rocksdb_transaction_db_minit(int module_number) 249 | { 250 | ROCKSDB_INIT_CLASS_ENTRY(rocksdb_transaction_db, "RocksDB\\TransactionDB", NULL, NULL, rocksdb_transaction_db_methods); 251 | ROCKSDB_SET_CLASS_CUSTOM_OBJECT(rocksdb_transaction_db, php_rocksdb_transaction_db_create_object, php_rocksdb_transaction_db_free_object, rocksdb_transaction_db_t, std); 252 | } -------------------------------------------------------------------------------- /rocksdb_write_batch.cc: -------------------------------------------------------------------------------- 1 | #include "php_rocksdb.h" 2 | #include "rocksdb/db.h" 3 | 4 | #include "error.h" 5 | 6 | using namespace rocksdb; 7 | 8 | typedef struct 9 | { 10 | WriteBatch *batch; 11 | zend_object std; 12 | } rocksdb_write_batch_t; 13 | 14 | zend_class_entry *rocksdb_write_batch_ce; 15 | zend_object_handlers rocksdb_write_batch_handlers; 16 | 17 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_write_void, 0, 0, 0) 18 | ZEND_END_ARG_INFO() 19 | 20 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_delete, 0, 0, 1) 21 | ZEND_ARG_INFO(0, key) 22 | ZEND_END_ARG_INFO() 23 | 24 | ZEND_BEGIN_ARG_INFO_EX(arginfo_rocksdb_put, 0, 0, 2) 25 | ZEND_ARG_INFO(0, key) 26 | ZEND_ARG_INFO(0, value) 27 | ZEND_END_ARG_INFO() 28 | 29 | static inline rocksdb_write_batch_t* php_rocksdb_write_batch_fetch_object(zend_object *obj) 30 | { 31 | return (rocksdb_write_batch_t *) ((char *) obj - rocksdb_write_batch_handlers.offset); 32 | } 33 | 34 | WriteBatch *php_rocksdb_write_batch_get_ptr(zval *zobject) 35 | { 36 | return php_rocksdb_write_batch_fetch_object(Z_OBJ_P(zobject))->batch; 37 | } 38 | 39 | void php_rocksdb_write_batch_set_ptr(zval *zobject, WriteBatch *batch) 40 | { 41 | php_rocksdb_write_batch_fetch_object(Z_OBJ_P(zobject))->batch = batch; 42 | } 43 | 44 | static void php_rocksdb_write_batch_free_object(zend_object *object) 45 | { 46 | zend_object_std_dtor(object); 47 | } 48 | 49 | static zend_object *php_rocksdb_write_batch_create_object(zend_class_entry *ce) 50 | { 51 | rocksdb_write_batch_t *batch = (rocksdb_write_batch_t *) zend_object_alloc(sizeof(rocksdb_write_batch_t), ce); 52 | zend_object_std_init(&batch->std, ce); 53 | object_properties_init(&batch->std, ce); 54 | batch->std.handlers = &rocksdb_write_batch_handlers; 55 | return &batch->std; 56 | } 57 | 58 | static PHP_METHOD(rocksdb_write_batch, __construct) 59 | { 60 | php_rocksdb_write_batch_set_ptr(ZEND_THIS, new WriteBatch()); 61 | } 62 | 63 | static PHP_METHOD(rocksdb_write_batch, delete) 64 | { 65 | char *key; 66 | size_t key_len; 67 | 68 | ZEND_PARSE_PARAMETERS_START(1, 1) 69 | Z_PARAM_STRING(key, key_len) 70 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 71 | 72 | WriteBatch *batch = php_rocksdb_write_batch_get_ptr(ZEND_THIS); 73 | 74 | Status s = batch->Delete(std::string(key, key_len)); 75 | if (!s.ok()) 76 | { 77 | zend_throw_exception(rocksdb_exception_ce, s.ToString().c_str(), ROCKSDB_BATCH_DELETE_ERROR); 78 | } 79 | 80 | RETURN_TRUE; 81 | } 82 | 83 | static PHP_METHOD(rocksdb_write_batch, put) 84 | { 85 | char *key; 86 | size_t key_len; 87 | char *value; 88 | size_t value_len; 89 | 90 | ZEND_PARSE_PARAMETERS_START(2, 2) 91 | Z_PARAM_STRING(key, key_len) 92 | Z_PARAM_STRING(value, value_len) 93 | ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE); 94 | 95 | WriteBatch *batch = php_rocksdb_write_batch_get_ptr(ZEND_THIS); 96 | 97 | Status s = batch->Put(std::string(key, key_len), std::string(value, value_len)); 98 | if (!s.ok()) 99 | { 100 | zend_throw_exception(rocksdb_exception_ce, s.ToString().c_str(), ROCKSDB_BATCH_DELETE_ERROR); 101 | } 102 | 103 | RETURN_TRUE; 104 | } 105 | 106 | static const zend_function_entry rocksdb_write_batch_methods[] = 107 | { 108 | PHP_ME(rocksdb_write_batch, __construct, arginfo_rocksdb_write_void, ZEND_ACC_PUBLIC) 109 | PHP_ME(rocksdb_write_batch, delete, arginfo_rocksdb_delete, ZEND_ACC_PUBLIC) 110 | PHP_ME(rocksdb_write_batch, put, arginfo_rocksdb_put, ZEND_ACC_PUBLIC) 111 | PHP_FE_END 112 | }; 113 | 114 | void php_rocksdb_write_batch_minit(int module_number) 115 | { 116 | ROCKSDB_INIT_CLASS_ENTRY(rocksdb_write_batch, "RocksDB\\WriteBatch", NULL, NULL, rocksdb_write_batch_methods); 117 | ROCKSDB_SET_CLASS_SERIALIZABLE(rocksdb_write_batch, zend_class_serialize_deny, zend_class_unserialize_deny); 118 | ROCKSDB_SET_CLASS_CLONEABLE(rocksdb_write_batch, rocksdb_zend_class_clone_deny); 119 | ROCKSDB_SET_CLASS_UNSET_PROPERTY_HANDLER(rocksdb_write_batch, rocksdb_zend_class_unset_property_deny); 120 | ROCKSDB_SET_CLASS_CUSTOM_OBJECT(rocksdb_write_batch, php_rocksdb_write_batch_create_object, php_rocksdb_write_batch_free_object, rocksdb_write_batch_t, std); 121 | } -------------------------------------------------------------------------------- /src/stringappend.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * A MergeOperator for rocksdb that implements string append. 3 | * @author Deon Nicholas (dnicholas@fb.com) 4 | * Copyright 2013 Facebook 5 | */ 6 | 7 | #include "stringappend.h" 8 | 9 | #include 10 | #include 11 | 12 | #include "rocksdb/slice.h" 13 | #include "rocksdb/merge_operator.h" 14 | // #include "utilities/merge_operators.h" 15 | 16 | namespace rocksdb { 17 | 18 | // Constructor: also specify the delimiter character. 19 | StringAppendOperator::StringAppendOperator(char delim_char) 20 | : delim_(delim_char) { 21 | } 22 | 23 | // Implementation for the merge operation (concatenates two strings) 24 | bool StringAppendOperator::Merge(const Slice& key, 25 | const Slice* existing_value, 26 | const Slice& value, 27 | std::string* new_value, 28 | Logger* logger) const { 29 | 30 | // Clear the *new_value for writing. 31 | assert(new_value); 32 | new_value->clear(); 33 | 34 | if (!existing_value) { 35 | // No existing_value. Set *new_value = value 36 | new_value->assign(value.data(),value.size()); 37 | } else { 38 | // Generic append (existing_value != null). 39 | // Reserve *new_value to correct size, and apply concatenation. 40 | new_value->reserve(existing_value->size() + 1 + value.size()); 41 | new_value->assign(existing_value->data(),existing_value->size()); 42 | new_value->append(1,delim_); 43 | new_value->append(value.data(), value.size()); 44 | } 45 | 46 | return true; 47 | } 48 | 49 | const char* StringAppendOperator::Name() const { 50 | return "StringAppendOperator"; 51 | } 52 | 53 | std::shared_ptr MergeOperators::CreateStringAppendOperator() { 54 | return std::make_shared(','); 55 | } 56 | 57 | } // namespace rocksdb 58 | -------------------------------------------------------------------------------- /test.php: -------------------------------------------------------------------------------- 1 | open($path); 8 | 9 | $ret = []; 10 | 11 | $iter = $db->newIterator("/e"); 12 | foreach ($iter as $key => $value) { 13 | var_dump($key, $value); 14 | } -------------------------------------------------------------------------------- /tests/CONTRIBUTION: -------------------------------------------------------------------------------- 1 | Tianfeng Han @ Swoole Group 2 | Twosee @ Swoole Group 3 | Xiaofeng Chu @ Zan Group 4 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | # PHP Unit-test 2 | 3 | Run these tests to make certain that the rocksdb extension you installed can work well. 4 | 5 | > The testing system was migrated from Swoole. 6 | 7 | ## How to run 8 | 9 | 1. just run `./start.sh api` 10 | 11 | ## Defaults 12 | 13 | | Config | Enable | 14 | | --------- | -------- | 15 | | show-diff | yes | 16 | | show-mem | yes | 17 | | show-slow | 1000(ms) | 18 | 19 | ## Log files 20 | 21 | | suffix | intro | 22 | | ------ | --------------------------------------------- | 23 | | diff | show the differents between output and expect | 24 | | out | script output | 25 | | exp | expect output | 26 | | log | all above | 27 | | php | php temp script file | 28 | 29 | ## Clean 30 | 31 | Run `./clean` to remove all of the tests log files. 32 | 33 | ## Contribute the test script 34 | 35 | Run `./new [test-script-filename]` 36 | 37 | E.g. : `./new ./rocksdb_db/test.phpt` 38 | 39 | It will generate the test script file and auto open on your ide (MacOS only). 40 | 41 | ![](https://ws1.sinaimg.cn/large/006DQdzWly1frvn56azn9g30rs0m8b29.gif) 42 | -------------------------------------------------------------------------------- /tests/clean: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace RocksdbTest; 14 | 15 | use ArrayAccess; 16 | use BadMethodCallException; 17 | use Closure; 18 | use Countable; 19 | use Exception; 20 | use RuntimeException; 21 | use Throwable; 22 | use Traversable; 23 | 24 | /** 25 | * Efficient assertions to validate the input/output of your methods. 26 | * 27 | * @method static bool nullOrString($value, $message = '') 28 | * @method static bool nullOrStringNotEmpty($value, $message = '') 29 | * @method static bool nullOrInteger($value, $message = '') 30 | * @method static bool nullOrIntegerish($value, $message = '') 31 | * @method static bool nullOrFloat($value, $message = '') 32 | * @method static bool nullOrNumeric($value, $message = '') 33 | * @method static bool nullOrNatural($value, $message = '') 34 | * @method static bool nullOrBoolean($value, $message = '') 35 | * @method static bool nullOrScalar($value, $message = '') 36 | * @method static bool nullOrObject($value, $message = '') 37 | * @method static bool nullOrResource($value, $type = null, $message = '') 38 | * @method static bool nullOrIsCallable($value, $message = '') 39 | * @method static bool nullOrIsArray($value, $message = '') 40 | * @method static bool nullOrIsTraversable($value, $message = '') 41 | * @method static bool nullOrIsArrayAccessible($value, $message = '') 42 | * @method static bool nullOrIsCountable($value, $message = '') 43 | * @method static bool nullOrIsIterable($value, $message = '') 44 | * @method static bool nullOrIsInstanceOf($value, $class, $message = '') 45 | * @method static bool nullOrNotInstanceOf($value, $class, $message = '') 46 | * @method static bool nullOrIsInstanceOfAny($value, $classes, $message = '') 47 | * @method static bool nullOrIsEmpty($value, $message = '') 48 | * @method static bool nullOrNotEmpty($value, $message = '') 49 | * @method static bool nullOrTrue($value, $message = '') 50 | * @method static bool nullOrFalse($value, $message = '') 51 | * @method static bool nullOrIp($value, $message = '') 52 | * @method static bool nullOrIpv4($value, $message = '') 53 | * @method static bool nullOrIpv6($value, $message = '') 54 | * @method static bool nullOrUniqueValues($values, $message = '') 55 | * @method static bool nullOrEq($value, $expect, $message = '') 56 | * @method static bool nullOrNotEq($value, $expect, $message = '') 57 | * @method static bool nullOrSame($value, $expect, $message = '') 58 | * @method static bool nullOrNotSame($value, $expect, $message = '') 59 | * @method static bool nullOrGreaterThan($value, $limit, $message = '') 60 | * @method static bool nullOrGreaterThanEq($value, $limit, $message = '') 61 | * @method static bool nullOrLessThan($value, $limit, $message = '') 62 | * @method static bool nullOrLessThanEq($value, $limit, $message = '') 63 | * @method static bool nullOrRange($value, $min, $max, $message = '') 64 | * @method static bool nullOrOneOf($value, $values, $message = '') 65 | * @method static bool nullOrContains($value, $subString, $message = '') 66 | * @method static bool nullOrNotContains($value, $subString, $message = '') 67 | * @method static bool nullOrNotWhitespaceOnly($value, $message = '') 68 | * @method static bool nullOrStartsWith($value, $prefix, $message = '') 69 | * @method static bool nullOrStartsWithLetter($value, $message = '') 70 | * @method static bool nullOrEndsWith($value, $suffix, $message = '') 71 | * @method static bool nullOrRegex($value, $pattern, $message = '') 72 | * @method static bool nullOrNotRegex($value, $pattern, $message = '') 73 | * @method static bool nullOrAlpha($value, $message = '') 74 | * @method static bool nullOrDigits($value, $message = '') 75 | * @method static bool nullOrAlnum($value, $message = '') 76 | * @method static bool nullOrLower($value, $message = '') 77 | * @method static bool nullOrUpper($value, $message = '') 78 | * @method static bool nullOrLength($value, $length, $message = '') 79 | * @method static bool nullOrMinLength($value, $min, $message = '') 80 | * @method static bool nullOrMaxLength($value, $max, $message = '') 81 | * @method static bool nullOrLengthBetween($value, $min, $max, $message = '') 82 | * @method static bool nullOrFileExists($value, $message = '') 83 | * @method static bool nullOrFile($value, $message = '') 84 | * @method static bool nullOrDirectory($value, $message = '') 85 | * @method static bool nullOrReadable($value, $message = '') 86 | * @method static bool nullOrWritable($value, $message = '') 87 | * @method static bool nullOrClassExists($value, $message = '') 88 | * @method static bool nullOrSubclassOf($value, $class, $message = '') 89 | * @method static bool nullOrInterfaceExists($value, $message = '') 90 | * @method static bool nullOrImplementsInterface($value, $interface, $message = '') 91 | * @method static bool nullOrPropertyExists($value, $property, $message = '') 92 | * @method static bool nullOrPropertyNotExists($value, $property, $message = '') 93 | * @method static bool nullOrMethodExists($value, $method, $message = '') 94 | * @method static bool nullOrMethodNotExists($value, $method, $message = '') 95 | * @method static bool nullOrKeyExists($value, $key, $message = '') 96 | * @method static bool nullOrKeyNotExists($value, $key, $message = '') 97 | * @method static bool nullOrCount($value, $key, $message = '') 98 | * @method static bool nullOrMinCount($value, $min, $message = '') 99 | * @method static bool nullOrMaxCount($value, $max, $message = '') 100 | * @method static bool nullOrIsList($value, $message = '') 101 | * @method static bool nullOrIsMap($value, $message = '') 102 | * @method static bool nullOrCountBetween($value, $min, $max, $message = '') 103 | * @method static bool nullOrUuid($values, $message = '') 104 | * @method static bool nullOrThrows($expression, $class = 'Exception', $message = '') 105 | * @method static bool allString($values, $message = '') 106 | * @method static bool allStringNotEmpty($values, $message = '') 107 | * @method static bool allInteger($values, $message = '') 108 | * @method static bool allIntegerish($values, $message = '') 109 | * @method static bool allFloat($values, $message = '') 110 | * @method static bool allNumeric($values, $message = '') 111 | * @method static bool allNatural($values, $message = '') 112 | * @method static bool allBoolean($values, $message = '') 113 | * @method static bool allScalar($values, $message = '') 114 | * @method static bool allObject($values, $message = '') 115 | * @method static bool allResource($values, $type = null, $message = '') 116 | * @method static bool allIsCallable($values, $message = '') 117 | * @method static bool allIsArray($values, $message = '') 118 | * @method static bool allIsTraversable($values, $message = '') 119 | * @method static bool allIsArrayAccessible($values, $message = '') 120 | * @method static bool allIsCountable($values, $message = '') 121 | * @method static bool allIsIterable($values, $message = '') 122 | * @method static bool allIsInstanceOf($values, $class, $message = '') 123 | * @method static bool allNotInstanceOf($values, $class, $message = '') 124 | * @method static bool allIsInstanceOfAny($values, $classes, $message = '') 125 | * @method static bool allNull($values, $message = '') 126 | * @method static bool allNotNull($values, $message = '') 127 | * @method static bool allIsEmpty($values, $message = '') 128 | * @method static bool allNotEmpty($values, $message = '') 129 | * @method static bool allTrue($values, $message = '') 130 | * @method static bool allFalse($values, $message = '') 131 | * @method static bool allIp($values, $message = '') 132 | * @method static bool allIpv4($values, $message = '') 133 | * @method static bool allIpv6($values, $message = '') 134 | * @method static bool allUniqueValues($values, $message = '') 135 | * @method static bool allEq($values, $expect, $message = '') 136 | * @method static bool allNotEq($values, $expect, $message = '') 137 | * @method static bool allSame($values, $expect, $message = '') 138 | * @method static bool allNotSame($values, $expect, $message = '') 139 | * @method static bool allGreaterThan($values, $limit, $message = '') 140 | * @method static bool allGreaterThanEq($values, $limit, $message = '') 141 | * @method static bool allLessThan($values, $limit, $message = '') 142 | * @method static bool allLessThanEq($values, $limit, $message = '') 143 | * @method static bool allRange($values, $min, $max, $message = '') 144 | * @method static bool allOneOf($values, $values, $message = '') 145 | * @method static bool allContains($values, $subString, $message = '') 146 | * @method static bool allNotContains($values, $subString, $message = '') 147 | * @method static bool allNotWhitespaceOnly($values, $message = '') 148 | * @method static bool allStartsWith($values, $prefix, $message = '') 149 | * @method static bool allStartsWithLetter($values, $message = '') 150 | * @method static bool allEndsWith($values, $suffix, $message = '') 151 | * @method static bool allRegex($values, $pattern, $message = '') 152 | * @method static bool allNotRegex($values, $pattern, $message = '') 153 | * @method static bool allAlpha($values, $message = '') 154 | * @method static bool allDigits($values, $message = '') 155 | * @method static bool allAlnum($values, $message = '') 156 | * @method static bool allLower($values, $message = '') 157 | * @method static bool allUpper($values, $message = '') 158 | * @method static bool allLength($values, $length, $message = '') 159 | * @method static bool allMinLength($values, $min, $message = '') 160 | * @method static bool allMaxLength($values, $max, $message = '') 161 | * @method static bool allLengthBetween($values, $min, $max, $message = '') 162 | * @method static bool allFileExists($values, $message = '') 163 | * @method static bool allFile($values, $message = '') 164 | * @method static bool allDirectory($values, $message = '') 165 | * @method static bool allReadable($values, $message = '') 166 | * @method static bool allWritable($values, $message = '') 167 | * @method static bool allClassExists($values, $message = '') 168 | * @method static bool allSubclassOf($values, $class, $message = '') 169 | * @method static bool allInterfaceExists($values, $message = '') 170 | * @method static bool allImplementsInterface($values, $interface, $message = '') 171 | * @method static bool allPropertyExists($values, $property, $message = '') 172 | * @method static bool allPropertyNotExists($values, $property, $message = '') 173 | * @method static bool allMethodExists($values, $method, $message = '') 174 | * @method static bool allMethodNotExists($values, $method, $message = '') 175 | * @method static bool allKeyExists($values, $key, $message = '') 176 | * @method static bool allKeyNotExists($values, $key, $message = '') 177 | * @method static bool allCount($values, $key, $message = '') 178 | * @method static bool allMinCount($values, $min, $message = '') 179 | * @method static bool allMaxCount($values, $max, $message = '') 180 | * @method static bool allCountBetween($values, $min, $max, $message = '') 181 | * @method static bool allIsList($values, $message = '') 182 | * @method static bool allIsMap($values, $message = '') 183 | * @method static bool allUuid($values, $message = '') 184 | * @method static bool allThrows($expressions, $class = 'Exception', $message = '') 185 | * 186 | * @since 2.0 187 | * 188 | * @author Bernhard Schussek 189 | */ 190 | class Assert 191 | { 192 | protected static $throwException = true; 193 | protected static $maxStringLength = 1024; 194 | 195 | public static function setThrowException(bool $b) 196 | { 197 | static::$throwException = $b; 198 | } 199 | 200 | public static function assert($value, $message = ''): bool 201 | { 202 | if (!$value) { 203 | static::reportInvalidArgument($message); 204 | return false; 205 | } 206 | return true; 207 | } 208 | 209 | public static function string($value, $message = ''): bool 210 | { 211 | if (!is_string($value)) { 212 | static::reportInvalidArgument(sprintf( 213 | $message ?: 'Expected a string. Got: %s', 214 | static::typeToString($value) 215 | )); 216 | return false; 217 | } 218 | return true; 219 | } 220 | 221 | public static function stringNotEmpty($value, $message = ''): bool 222 | { 223 | return static::string($value, $message) && static::notEq($value, '', $message); 224 | } 225 | 226 | public static function integer($value, $message = ''): bool 227 | { 228 | if (!is_int($value)) { 229 | static::reportInvalidArgument(sprintf( 230 | $message ?: 'Expected an integer. Got: %s', 231 | static::typeToString($value) 232 | )); 233 | return false; 234 | } 235 | return true; 236 | } 237 | 238 | public static function integerish($value, $message = ''): bool 239 | { 240 | if (!is_numeric($value) || $value != (int)$value) { 241 | static::reportInvalidArgument(sprintf( 242 | $message ?: 'Expected an integerish value. Got: %s', 243 | static::typeToString($value) 244 | )); 245 | return false; 246 | } 247 | return true; 248 | } 249 | 250 | public static function float($value, $message = ''): bool 251 | { 252 | if (!is_float($value)) { 253 | static::reportInvalidArgument(sprintf( 254 | $message ?: 'Expected a float. Got: %s', 255 | static::typeToString($value) 256 | )); 257 | return false; 258 | } 259 | return true; 260 | } 261 | 262 | public static function numeric($value, $message = ''): bool 263 | { 264 | if (!is_numeric($value)) { 265 | static::reportInvalidArgument(sprintf( 266 | $message ?: 'Expected a numeric. Got: %s', 267 | static::typeToString($value) 268 | )); 269 | return false; 270 | } 271 | return true; 272 | } 273 | 274 | public static function natural($value, $message = ''): bool 275 | { 276 | if (!is_int($value) || $value < 0) { 277 | static::reportInvalidArgument(sprintf( 278 | $message ?: 'Expected a non-negative integer. Got %s', 279 | static::valueToString($value) 280 | )); 281 | return false; 282 | } 283 | return true; 284 | } 285 | 286 | public static function boolean($value, $message = ''): bool 287 | { 288 | if (!is_bool($value)) { 289 | static::reportInvalidArgument(sprintf( 290 | $message ?: 'Expected a boolean. Got: %s', 291 | static::typeToString($value) 292 | )); 293 | return false; 294 | } 295 | return true; 296 | } 297 | 298 | public static function scalar($value, $message = ''): bool 299 | { 300 | if (!is_scalar($value)) { 301 | static::reportInvalidArgument(sprintf( 302 | $message ?: 'Expected a scalar. Got: %s', 303 | static::typeToString($value) 304 | )); 305 | return false; 306 | } 307 | return true; 308 | } 309 | 310 | public static function object($value, $message = ''): bool 311 | { 312 | if (!is_object($value)) { 313 | static::reportInvalidArgument(sprintf( 314 | $message ?: 'Expected an object. Got: %s', 315 | static::typeToString($value) 316 | )); 317 | return false; 318 | } 319 | return true; 320 | } 321 | 322 | public static function resource($value, $type = null, $message = ''): bool 323 | { 324 | if (!is_resource($value)) { 325 | static::reportInvalidArgument(sprintf( 326 | $message ?: 'Expected a resource. Got: %s', 327 | static::typeToString($value) 328 | )); 329 | return false; 330 | } 331 | if ($type && $type !== get_resource_type($value)) { 332 | static::reportInvalidArgument(sprintf( 333 | $message ?: 'Expected a resource of type %2$s. Got: %s', 334 | static::typeToString($value), 335 | $type 336 | )); 337 | return false; 338 | } 339 | return true; 340 | } 341 | 342 | public static function isCallable($value, $message = ''): bool 343 | { 344 | if (!is_callable($value)) { 345 | static::reportInvalidArgument(sprintf( 346 | $message ?: 'Expected a callable. Got: %s', 347 | static::typeToString($value) 348 | )); 349 | return false; 350 | } 351 | return true; 352 | } 353 | 354 | public static function isArray($value, $message = ''): bool 355 | { 356 | if (!is_array($value)) { 357 | static::reportInvalidArgument(sprintf( 358 | $message ?: 'Expected an array. Got: %s', 359 | static::typeToString($value) 360 | )); 361 | return false; 362 | } 363 | return true; 364 | } 365 | 366 | public static function isArrayAccessible($value, $message = ''): bool 367 | { 368 | if (!is_array($value) && !($value instanceof ArrayAccess)) { 369 | static::reportInvalidArgument(sprintf( 370 | $message ?: 'Expected an array accessible. Got: %s', 371 | static::typeToString($value) 372 | )); 373 | return false; 374 | } 375 | return true; 376 | } 377 | 378 | public static function isCountable($value, $message = ''): bool 379 | { 380 | if (!is_array($value) && !($value instanceof Countable)) { 381 | static::reportInvalidArgument(sprintf( 382 | $message ?: 'Expected a countable. Got: %s', 383 | static::typeToString($value) 384 | )); 385 | return false; 386 | } 387 | return true; 388 | } 389 | 390 | public static function isIterable($value, $message = ''): bool 391 | { 392 | if (!is_array($value) && !($value instanceof Traversable)) { 393 | static::reportInvalidArgument(sprintf( 394 | $message ?: 'Expected an iterable. Got: %s', 395 | static::typeToString($value) 396 | )); 397 | return false; 398 | } 399 | return true; 400 | } 401 | 402 | public static function isInstanceOf($value, $class, $message = ''): bool 403 | { 404 | if (!($value instanceof $class)) { 405 | static::reportInvalidArgument(sprintf( 406 | $message ?: 'Expected an instance of %2$s. Got: %s', 407 | static::typeToString($value), 408 | $class 409 | )); 410 | return false; 411 | } 412 | return true; 413 | } 414 | 415 | public static function notInstanceOf($value, $class, $message = ''): bool 416 | { 417 | if ($value instanceof $class) { 418 | static::reportInvalidArgument(sprintf( 419 | $message ?: 'Expected an instance other than %2$s. Got: %s', 420 | static::typeToString($value), 421 | $class 422 | )); 423 | return false; 424 | } 425 | return true; 426 | } 427 | 428 | public static function isInstanceOfAny($value, array $classes, $message = ''): bool 429 | { 430 | foreach ($classes as $class) { 431 | if ($value instanceof $class) { 432 | return true; 433 | } 434 | } 435 | static::reportInvalidArgument(sprintf( 436 | $message ?: 'Expected an instance of any of %2$s. Got: %s', 437 | static::typeToString($value), 438 | implode(', ', array_map(['static', 'valueToString'], $classes)) 439 | )); 440 | return false; 441 | } 442 | 443 | public static function isEmpty($value, $message = ''): bool 444 | { 445 | if (!empty($value)) { 446 | static::reportInvalidArgument(sprintf( 447 | $message ?: 'Expected an empty value. Got: %s', 448 | static::valueToString($value) 449 | )); 450 | return false; 451 | } 452 | return true; 453 | } 454 | 455 | public static function notEmpty($value, $message = ''): bool 456 | { 457 | if (empty($value)) { 458 | static::reportInvalidArgument(sprintf( 459 | $message ?: 'Expected a non-empty value. Got: %s', 460 | static::valueToString($value) 461 | )); 462 | return false; 463 | } 464 | return true; 465 | } 466 | 467 | public static function null($value, $message = ''): bool 468 | { 469 | if (null !== $value) { 470 | static::reportInvalidArgument(sprintf( 471 | $message ?: 'Expected null. Got: %s', 472 | static::valueToString($value) 473 | )); 474 | return false; 475 | } 476 | return true; 477 | } 478 | 479 | public static function notNull($value, $message = ''): bool 480 | { 481 | if (null === $value) { 482 | static::reportInvalidArgument( 483 | $message ?: 'Expected a value other than null.' 484 | ); 485 | return false; 486 | } 487 | return true; 488 | } 489 | 490 | public static function true($value, $message = ''): bool 491 | { 492 | if (true !== $value) { 493 | static::reportInvalidArgument(sprintf( 494 | $message ?: 'Expected a value to be true. Got: %s', 495 | static::valueToString($value) 496 | )); 497 | return false; 498 | } 499 | return true; 500 | } 501 | 502 | public static function false($value, $message = ''): bool 503 | { 504 | if (false !== $value) { 505 | static::reportInvalidArgument(sprintf( 506 | $message ?: 'Expected a value to be false. Got: %s', 507 | static::valueToString($value) 508 | )); 509 | return false; 510 | } 511 | return true; 512 | } 513 | 514 | public static function ip($value, $message = ''): bool 515 | { 516 | if (false === filter_var($value, FILTER_VALIDATE_IP)) { 517 | static::reportInvalidArgument(sprintf( 518 | $message ?: 'Expected a value to be an IP. Got: %s', 519 | static::valueToString($value) 520 | )); 521 | return false; 522 | } 523 | return true; 524 | } 525 | 526 | public static function ipv4($value, $message = ''): bool 527 | { 528 | if (false === filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { 529 | static::reportInvalidArgument(sprintf( 530 | $message ?: 'Expected a value to be an IPv4. Got: %s', 531 | static::valueToString($value) 532 | )); 533 | return false; 534 | } 535 | return true; 536 | } 537 | 538 | public static function ipv6($value, $message = ''): bool 539 | { 540 | if (false === filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { 541 | static::reportInvalidArgument(sprintf( 542 | $message ?: 'Expected a value to be an IPv6. Got %s', 543 | static::valueToString($value) 544 | )); 545 | return false; 546 | } 547 | return true; 548 | } 549 | 550 | public static function uniqueValues(array $values, $message = ''): bool 551 | { 552 | $allValues = count($values); 553 | $uniqueValues = count(array_unique($values)); 554 | if ($allValues !== $uniqueValues) { 555 | $difference = $allValues - $uniqueValues; 556 | static::reportInvalidArgument(sprintf( 557 | $message ?: 'Expected an array of unique values, but %s of them %s duplicated', 558 | $difference, 559 | (1 === $difference ? 'is' : 'are') 560 | )); 561 | return false; 562 | } 563 | return true; 564 | } 565 | 566 | public static function eq($value, $expect, $message = ''): bool 567 | { 568 | if ($expect != $value) { 569 | static::reportInvalidArgument(sprintf( 570 | $message ?: 'Expected a value equal to %2$s. Got: %s', 571 | static::valueToString($value), 572 | static::valueToString($expect) 573 | )); 574 | return false; 575 | } 576 | return true; 577 | } 578 | 579 | public static function notEq($value, $expect, $message = ''): bool 580 | { 581 | if ($expect == $value) { 582 | static::reportInvalidArgument(sprintf( 583 | $message ?: 'Expected a different value than %s.', 584 | static::valueToString($expect) 585 | )); 586 | return false; 587 | } 588 | return true; 589 | } 590 | 591 | public static function same($value, $expect, $message = ''): bool 592 | { 593 | if ($expect !== $value) { 594 | static::reportInvalidArgument(sprintf( 595 | $message ?: 'Expected a value identical to %2$s. Got: %s', 596 | static::valueToString($value), 597 | static::valueToString($expect) 598 | )); 599 | return false; 600 | } 601 | return true; 602 | } 603 | 604 | public static function notSame($value, $expect, $message = ''): bool 605 | { 606 | if ($expect === $value) { 607 | static::reportInvalidArgument(sprintf( 608 | $message ?: 'Expected a value not identical to %s.', 609 | static::valueToString($expect) 610 | )); 611 | return false; 612 | } 613 | return true; 614 | } 615 | 616 | public static function greaterThan($value, $limit, $message = ''): bool 617 | { 618 | if ($value <= $limit) { 619 | static::reportInvalidArgument(sprintf( 620 | $message ?: 'Expected a value greater than %2$s. Got: %s', 621 | static::valueToString($value), 622 | static::valueToString($limit) 623 | )); 624 | return false; 625 | } 626 | return true; 627 | } 628 | 629 | public static function greaterThanEq($value, $limit, $message = ''): bool 630 | { 631 | if ($value < $limit) { 632 | static::reportInvalidArgument(sprintf( 633 | $message ?: 'Expected a value greater than or equal to %2$s. Got: %s', 634 | static::valueToString($value), 635 | static::valueToString($limit) 636 | )); 637 | return false; 638 | } 639 | return true; 640 | } 641 | 642 | public static function lessThan($value, $limit, $message = ''): bool 643 | { 644 | if ($value >= $limit) { 645 | static::reportInvalidArgument(sprintf( 646 | $message ?: 'Expected a value less than %2$s. Got: %s', 647 | static::valueToString($value), 648 | static::valueToString($limit) 649 | )); 650 | return false; 651 | } 652 | return true; 653 | } 654 | 655 | public static function lessThanEq($value, $limit, $message = ''): bool 656 | { 657 | if ($value > $limit) { 658 | static::reportInvalidArgument(sprintf( 659 | $message ?: 'Expected a value less than or equal to %2$s. Got: %s', 660 | static::valueToString($value), 661 | static::valueToString($limit) 662 | )); 663 | return false; 664 | } 665 | return true; 666 | } 667 | 668 | public static function range($value, $min, $max, $message = ''): bool 669 | { 670 | if ($value < $min || $value > $max) { 671 | static::reportInvalidArgument(sprintf( 672 | $message ?: 'Expected a value between %2$s and %3$s. Got: %s', 673 | static::valueToString($value), 674 | static::valueToString($min), 675 | static::valueToString($max) 676 | )); 677 | return false; 678 | } 679 | return true; 680 | } 681 | 682 | public static function approximate($value, $actual, float $ratio = 0.1): bool 683 | { 684 | $ret = $actual * (1 - $ratio) < $value && $actual * (1 + $ratio) > $value; 685 | if (!$ret) { 686 | static::reportInvalidArgument( 687 | "Expected a value approximate {$value}, but got {$actual}\n" 688 | ); 689 | } 690 | return $ret; 691 | } 692 | 693 | public static function oneOf($value, array $values, $message = ''): bool 694 | { 695 | if (!in_array($value, $values, true)) { 696 | static::reportInvalidArgument(sprintf( 697 | $message ?: 'Expected one of: %2$s. Got: %s', 698 | static::valueToString($value), 699 | implode(', ', array_map(['static', 'valueToString'], $values)) 700 | )); 701 | return false; 702 | } 703 | return true; 704 | } 705 | 706 | public static function contains($value, $subString, $message = ''): bool 707 | { 708 | if (false === strpos($value, $subString)) { 709 | static::reportInvalidArgument(sprintf( 710 | $message ?: 'Expected a value to contain %2$s. Got: %s', 711 | static::valueToString($value), 712 | static::valueToString($subString) 713 | )); 714 | return false; 715 | } 716 | return true; 717 | } 718 | 719 | public static function notContains($value, $subString, $message = ''): bool 720 | { 721 | if (false !== strpos($value, $subString)) { 722 | static::reportInvalidArgument(sprintf( 723 | $message ?: '%2$s was not expected to be contained in a value. Got: %s', 724 | static::valueToString($value), 725 | static::valueToString($subString) 726 | )); 727 | return false; 728 | } 729 | return true; 730 | } 731 | 732 | public static function notWhitespaceOnly($value, $message = ''): bool 733 | { 734 | if (preg_match('/^\s*$/', $value)) { 735 | static::reportInvalidArgument(sprintf( 736 | $message ?: 'Expected a non-whitespace string. Got: %s', 737 | static::valueToString($value) 738 | )); 739 | return false; 740 | } 741 | return true; 742 | } 743 | 744 | public static function startsWith($value, $prefix, $message = ''): bool 745 | { 746 | if (0 !== strpos($value, $prefix)) { 747 | static::reportInvalidArgument(sprintf( 748 | $message ?: 'Expected a value to start with %2$s. Got: %s', 749 | static::valueToString($value), 750 | static::valueToString($prefix) 751 | )); 752 | return false; 753 | } 754 | return true; 755 | } 756 | 757 | public static function startsWithLetter($value, $message = ''): bool 758 | { 759 | $valid = isset($value[0]); 760 | 761 | if ($valid) { 762 | $locale = setlocale(LC_CTYPE, 0); 763 | setlocale(LC_CTYPE, 'C'); 764 | $valid = ctype_alpha($value[0]); 765 | setlocale(LC_CTYPE, $locale); 766 | } 767 | 768 | if (!$valid) { 769 | static::reportInvalidArgument(sprintf( 770 | $message ?: 'Expected a value to start with a letter. Got: %s', 771 | static::valueToString($value) 772 | )); 773 | return false; 774 | } 775 | return true; 776 | } 777 | 778 | public static function endsWith($value, $suffix, $message = ''): bool 779 | { 780 | if ($suffix !== substr($value, -static::strlen($suffix))) { 781 | static::reportInvalidArgument(sprintf( 782 | $message ?: 'Expected a value to end with %2$s. Got: %s', 783 | static::valueToString($value), 784 | static::valueToString($suffix) 785 | )); 786 | return false; 787 | } 788 | return true; 789 | } 790 | 791 | public static function regex($value, $pattern, $message = ''): bool 792 | { 793 | if (!preg_match($pattern, $value)) { 794 | static::reportInvalidArgument(sprintf( 795 | $message ?: 'The value %s does not match the expected pattern.', 796 | static::valueToString($value) 797 | )); 798 | return false; 799 | } 800 | return true; 801 | } 802 | 803 | public static function notRegex($value, $pattern, $message = ''): bool 804 | { 805 | if (preg_match($pattern, $value, $matches, PREG_OFFSET_CAPTURE)) { 806 | static::reportInvalidArgument(sprintf( 807 | $message ?: 'The value %s matches the pattern %s (at offset %d).', 808 | static::valueToString($value), 809 | static::valueToString($pattern), 810 | $matches[0][1] 811 | )); 812 | return false; 813 | } 814 | return true; 815 | } 816 | 817 | public static function alpha($value, $message = ''): bool 818 | { 819 | $locale = setlocale(LC_CTYPE, 0); 820 | setlocale(LC_CTYPE, 'C'); 821 | $valid = !ctype_alpha($value); 822 | setlocale(LC_CTYPE, $locale); 823 | 824 | if ($valid) { 825 | static::reportInvalidArgument(sprintf( 826 | $message ?: 'Expected a value to contain only letters. Got: %s', 827 | static::valueToString($value) 828 | )); 829 | return false; 830 | } 831 | return true; 832 | } 833 | 834 | public static function digits($value, $message = ''): bool 835 | { 836 | $locale = setlocale(LC_CTYPE, 0); 837 | setlocale(LC_CTYPE, 'C'); 838 | $valid = !ctype_digit($value); 839 | setlocale(LC_CTYPE, $locale); 840 | 841 | if ($valid) { 842 | static::reportInvalidArgument(sprintf( 843 | $message ?: 'Expected a value to contain digits only. Got: %s', 844 | static::valueToString($value) 845 | )); 846 | return false; 847 | } 848 | return true; 849 | } 850 | 851 | public static function alnum($value, $message = ''): bool 852 | { 853 | $locale = setlocale(LC_CTYPE, 0); 854 | setlocale(LC_CTYPE, 'C'); 855 | $valid = !ctype_alnum($value); 856 | setlocale(LC_CTYPE, $locale); 857 | 858 | if ($valid) { 859 | static::reportInvalidArgument(sprintf( 860 | $message ?: 'Expected a value to contain letters and digits only. Got: %s', 861 | static::valueToString($value) 862 | )); 863 | return false; 864 | } 865 | return true; 866 | } 867 | 868 | public static function lower($value, $message = ''): bool 869 | { 870 | $locale = setlocale(LC_CTYPE, 0); 871 | setlocale(LC_CTYPE, 'C'); 872 | $valid = !ctype_lower($value); 873 | setlocale(LC_CTYPE, $locale); 874 | 875 | if ($valid) { 876 | static::reportInvalidArgument(sprintf( 877 | $message ?: 'Expected a value to contain lowercase characters only. Got: %s', 878 | static::valueToString($value) 879 | )); 880 | return false; 881 | } 882 | return true; 883 | } 884 | 885 | public static function upper($value, $message = ''): bool 886 | { 887 | $locale = setlocale(LC_CTYPE, 0); 888 | setlocale(LC_CTYPE, 'C'); 889 | $valid = !ctype_upper($value); 890 | setlocale(LC_CTYPE, $locale); 891 | 892 | if ($valid) { 893 | static::reportInvalidArgument(sprintf( 894 | $message ?: 'Expected a value to contain uppercase characters only. Got: %s', 895 | static::valueToString($value) 896 | )); 897 | return false; 898 | } 899 | return true; 900 | } 901 | 902 | public static function length($value, $length, $message = ''): bool 903 | { 904 | if ($length !== static::strlen($value)) { 905 | static::reportInvalidArgument(sprintf( 906 | $message ?: 'Expected a value to contain %2$s characters. Got: %s', 907 | static::valueToString($value), 908 | $length 909 | )); 910 | return false; 911 | } 912 | return true; 913 | } 914 | 915 | public static function minLength($value, $min, $message = ''): bool 916 | { 917 | if (static::strlen($value) < $min) { 918 | static::reportInvalidArgument(sprintf( 919 | $message ?: 'Expected a value to contain at least %2$s characters. Got: %s', 920 | static::valueToString($value), 921 | $min 922 | )); 923 | return false; 924 | } 925 | return true; 926 | } 927 | 928 | public static function maxLength($value, $max, $message = ''): bool 929 | { 930 | if (static::strlen($value) > $max) { 931 | static::reportInvalidArgument(sprintf( 932 | $message ?: 'Expected a value to contain at most %2$s characters. Got: %s', 933 | static::valueToString($value), 934 | $max 935 | )); 936 | return false; 937 | } 938 | return true; 939 | } 940 | 941 | public static function lengthBetween($value, $min, $max, $message = ''): bool 942 | { 943 | $length = static::strlen($value); 944 | 945 | if ($length < $min || $length > $max) { 946 | static::reportInvalidArgument(sprintf( 947 | $message ?: 'Expected a value to contain between %2$s and %3$s characters. Got: %s', 948 | static::valueToString($value), 949 | $min, 950 | $max 951 | )); 952 | return false; 953 | } 954 | return true; 955 | } 956 | 957 | public static function fileExists($value, $message = ''): bool 958 | { 959 | static::string($value); 960 | 961 | if (!file_exists($value)) { 962 | static::reportInvalidArgument(sprintf( 963 | $message ?: 'The file %s does not exist.', 964 | static::valueToString($value) 965 | )); 966 | return false; 967 | } 968 | return true; 969 | } 970 | 971 | public static function file($value, $message = ''): bool 972 | { 973 | static::fileExists($value, $message); 974 | 975 | if (!is_file($value)) { 976 | static::reportInvalidArgument(sprintf( 977 | $message ?: 'The path %s is not a file.', 978 | static::valueToString($value) 979 | )); 980 | return false; 981 | } 982 | return true; 983 | } 984 | 985 | public static function directory($value, $message = ''): bool 986 | { 987 | static::fileExists($value, $message); 988 | 989 | if (!is_dir($value)) { 990 | static::reportInvalidArgument(sprintf( 991 | $message ?: 'The path %s is no directory.', 992 | static::valueToString($value) 993 | )); 994 | return false; 995 | } 996 | return true; 997 | } 998 | 999 | public static function readable($value, $message = ''): bool 1000 | { 1001 | if (!is_readable($value)) { 1002 | static::reportInvalidArgument(sprintf( 1003 | $message ?: 'The path %s is not readable.', 1004 | static::valueToString($value) 1005 | )); 1006 | return false; 1007 | } 1008 | return true; 1009 | } 1010 | 1011 | public static function writable($value, $message = ''): bool 1012 | { 1013 | if (!is_writable($value)) { 1014 | static::reportInvalidArgument(sprintf( 1015 | $message ?: 'The path %s is not writable.', 1016 | static::valueToString($value) 1017 | )); 1018 | return false; 1019 | } 1020 | return true; 1021 | } 1022 | 1023 | public static function classExists($value, $message = ''): bool 1024 | { 1025 | if (!class_exists($value)) { 1026 | static::reportInvalidArgument(sprintf( 1027 | $message ?: 'Expected an existing class name. Got: %s', 1028 | static::valueToString($value) 1029 | )); 1030 | return false; 1031 | } 1032 | return true; 1033 | } 1034 | 1035 | public static function subclassOf($value, $class, $message = ''): bool 1036 | { 1037 | if (!is_subclass_of($value, $class)) { 1038 | static::reportInvalidArgument(sprintf( 1039 | $message ?: 'Expected a sub-class of %2$s. Got: %s', 1040 | static::valueToString($value), 1041 | static::valueToString($class) 1042 | )); 1043 | return false; 1044 | } 1045 | return true; 1046 | } 1047 | 1048 | public static function interfaceExists($value, $message = ''): bool 1049 | { 1050 | if (!interface_exists($value)) { 1051 | static::reportInvalidArgument(sprintf( 1052 | $message ?: 'Expected an existing interface name. got %s', 1053 | static::valueToString($value) 1054 | )); 1055 | return false; 1056 | } 1057 | return true; 1058 | } 1059 | 1060 | public static function implementsInterface($value, $interface, $message = ''): bool 1061 | { 1062 | if (!in_array($interface, class_implements($value))) { 1063 | static::reportInvalidArgument(sprintf( 1064 | $message ?: 'Expected an implementation of %2$s. Got: %s', 1065 | static::valueToString($value), 1066 | static::valueToString($interface) 1067 | )); 1068 | return false; 1069 | } 1070 | return true; 1071 | } 1072 | 1073 | public static function propertyExists($classOrObject, $property, $message = ''): bool 1074 | { 1075 | if (!property_exists($classOrObject, $property)) { 1076 | static::reportInvalidArgument(sprintf( 1077 | $message ?: 'Expected the property %s to exist.', 1078 | static::valueToString($property) 1079 | )); 1080 | return false; 1081 | } 1082 | return true; 1083 | } 1084 | 1085 | public static function propertyNotExists($classOrObject, $property, $message = ''): bool 1086 | { 1087 | if (property_exists($classOrObject, $property)) { 1088 | static::reportInvalidArgument(sprintf( 1089 | $message ?: 'Expected the property %s to not exist.', 1090 | static::valueToString($property) 1091 | )); 1092 | return false; 1093 | } 1094 | return true; 1095 | } 1096 | 1097 | public static function methodExists($classOrObject, $method, $message = ''): bool 1098 | { 1099 | if (!method_exists($classOrObject, $method)) { 1100 | static::reportInvalidArgument(sprintf( 1101 | $message ?: 'Expected the method %s to exist.', 1102 | static::valueToString($method) 1103 | )); 1104 | return false; 1105 | } 1106 | return true; 1107 | } 1108 | 1109 | public static function methodNotExists($classOrObject, $method, $message = ''): bool 1110 | { 1111 | if (method_exists($classOrObject, $method)) { 1112 | static::reportInvalidArgument(sprintf( 1113 | $message ?: 'Expected the method %s to not exist.', 1114 | static::valueToString($method) 1115 | )); 1116 | return false; 1117 | } 1118 | return true; 1119 | } 1120 | 1121 | public static function keyExists($array, $key, $message = ''): bool 1122 | { 1123 | if (!(isset($array[$key]) || array_key_exists($key, $array))) { 1124 | static::reportInvalidArgument(sprintf( 1125 | $message ?: 'Expected the key %s to exist.', 1126 | static::valueToString($key) 1127 | )); 1128 | return false; 1129 | } 1130 | return true; 1131 | } 1132 | 1133 | public static function keyNotExists($array, $key, $message = ''): bool 1134 | { 1135 | if (isset($array[$key]) || array_key_exists($key, $array)) { 1136 | static::reportInvalidArgument(sprintf( 1137 | $message ?: 'Expected the key %s to not exist.', 1138 | static::valueToString($key) 1139 | )); 1140 | return false; 1141 | } 1142 | return true; 1143 | } 1144 | 1145 | public static function count($array, $number, $message = ''): bool 1146 | { 1147 | return static::eq( 1148 | count($array), 1149 | $number, 1150 | $message ?: sprintf('Expected an array to contain %d elements. Got: %d.', $number, count($array)) 1151 | ); 1152 | } 1153 | 1154 | public static function minCount($array, $min, $message = ''): bool 1155 | { 1156 | if (count($array) < $min) { 1157 | static::reportInvalidArgument(sprintf( 1158 | $message ?: 'Expected an array to contain at least %2$d elements. Got: %d', 1159 | count($array), 1160 | $min 1161 | )); 1162 | return false; 1163 | } 1164 | return true; 1165 | } 1166 | 1167 | public static function maxCount($array, $max, $message = ''): bool 1168 | { 1169 | if (count($array) > $max) { 1170 | static::reportInvalidArgument(sprintf( 1171 | $message ?: 'Expected an array to contain at most %2$d elements. Got: %d', 1172 | count($array), 1173 | $max 1174 | )); 1175 | return false; 1176 | } 1177 | return true; 1178 | } 1179 | 1180 | public static function countBetween($array, $min, $max, $message = ''): bool 1181 | { 1182 | $count = count($array); 1183 | 1184 | if ($count < $min || $count > $max) { 1185 | static::reportInvalidArgument(sprintf( 1186 | $message ?: 'Expected an array to contain between %2$d and %3$d elements. Got: %d', 1187 | $count, 1188 | $min, 1189 | $max 1190 | )); 1191 | return false; 1192 | } 1193 | return true; 1194 | } 1195 | 1196 | public static function isList($array, $message = ''): bool 1197 | { 1198 | if (!is_array($array) || !$array || array_keys($array) !== range(0, count($array) - 1)) { 1199 | static::reportInvalidArgument( 1200 | $message ?: 'Expected list - non-associative array.' 1201 | ); 1202 | return false; 1203 | } 1204 | return true; 1205 | } 1206 | 1207 | public static function isMap($array, $message = ''): bool 1208 | { 1209 | if ( 1210 | !is_array($array) || 1211 | !$array || 1212 | array_keys($array) !== array_filter(array_keys($array), function ($key) { 1213 | return is_string($key); 1214 | }) 1215 | ) { 1216 | static::reportInvalidArgument( 1217 | $message ?: 'Expected map - associative array with string keys.' 1218 | ); 1219 | return false; 1220 | } 1221 | return true; 1222 | } 1223 | 1224 | public static function uuid($value, $message = ''): bool 1225 | { 1226 | $value = str_replace(['urn:', 'uuid:', '{', '}'], '', $value); 1227 | 1228 | // The nil UUID is special form of UUID that is specified to have all 1229 | // 128 bits set to zero. 1230 | if ('00000000-0000-0000-0000-000000000000' === $value) { 1231 | return true; 1232 | } 1233 | 1234 | if (!preg_match('/^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$/', $value)) { 1235 | static::reportInvalidArgument(sprintf( 1236 | $message ?: 'Value %s is not a valid UUID.', 1237 | static::valueToString($value) 1238 | )); 1239 | return false; 1240 | } 1241 | return true; 1242 | } 1243 | 1244 | public static function throws(Closure $expression, $class = 'Exception', $message = ''): bool 1245 | { 1246 | static::string($class); 1247 | 1248 | $actual = 'none'; 1249 | 1250 | try { 1251 | $expression(); 1252 | } catch (Exception $e) { 1253 | $actual = get_class($e); 1254 | if ($e instanceof $class) { 1255 | return true; 1256 | } 1257 | } catch (Throwable $e) { 1258 | $actual = get_class($e); 1259 | if ($e instanceof $class) { 1260 | return true; 1261 | } 1262 | } 1263 | 1264 | static::reportInvalidArgument($message ?: sprintf( 1265 | 'Expected to throw "%s", got "%s"', 1266 | $class, 1267 | $actual 1268 | )); 1269 | return false; 1270 | } 1271 | 1272 | public static function __callStatic($name, $arguments): bool 1273 | { 1274 | if ('nullOr' === substr($name, 0, 6)) { 1275 | if (null !== $arguments[0]) { 1276 | $method = lcfirst(substr($name, 6)); 1277 | if (!call_user_func_array(['static', $method], $arguments)) { 1278 | return false; 1279 | } 1280 | } 1281 | 1282 | return true; 1283 | } 1284 | 1285 | if ('all' === substr($name, 0, 3)) { 1286 | if (!static::isIterable($arguments[0])) { 1287 | return false; 1288 | } 1289 | 1290 | $method = lcfirst(substr($name, 3)); 1291 | $args = $arguments; 1292 | 1293 | foreach ($arguments[0] as $entry) { 1294 | $args[0] = $entry; 1295 | if (!call_user_func_array(['static', $method], $args)) { 1296 | return false; 1297 | } 1298 | } 1299 | 1300 | return true; 1301 | } 1302 | 1303 | throw new BadMethodCallException('No such method: ' . $name); 1304 | } 1305 | 1306 | protected static function valueToString($value): string 1307 | { 1308 | if (null === $value) { 1309 | return 'null'; 1310 | } 1311 | 1312 | if (true === $value) { 1313 | return 'true'; 1314 | } 1315 | 1316 | if (false === $value) { 1317 | return 'false'; 1318 | } 1319 | 1320 | if (is_array($value)) { 1321 | return 'array(' . count($value) . ')'; 1322 | } 1323 | 1324 | if (is_object($value)) { 1325 | if (method_exists($value, '__toString')) { 1326 | return get_class($value) . ': ' . self::valueToString($value->__toString()); 1327 | } 1328 | return get_class($value); 1329 | } 1330 | 1331 | if (is_resource($value)) { 1332 | return 'resource'; 1333 | } 1334 | 1335 | if (is_string($value)) { 1336 | $length = strlen($value); 1337 | if ($length > static::$maxStringLength) { 1338 | $value = substr($value, 0, static::$maxStringLength) . '...'; 1339 | } 1340 | return 'string(' . $length . ') "' . $value . '"'; 1341 | } 1342 | 1343 | return (string)$value; 1344 | } 1345 | 1346 | protected static function typeToString($value): string 1347 | { 1348 | return is_object($value) ? get_class($value) : gettype($value); 1349 | } 1350 | 1351 | protected static function strlen($value): int 1352 | { 1353 | if (!function_exists('mb_detect_encoding')) { 1354 | return strlen($value); 1355 | } 1356 | 1357 | if (false === $encoding = mb_detect_encoding($value)) { 1358 | return strlen($value); 1359 | } 1360 | 1361 | return mb_strwidth($value, $encoding); 1362 | } 1363 | 1364 | protected static function reportInvalidArgument(string $message = '') 1365 | { 1366 | $e = new RuntimeException($message); 1367 | if (static::$throwException) { 1368 | throw $e; 1369 | } else { 1370 | $file = $e->getFile(); 1371 | $line = $e->getLine(); 1372 | $msg = $e->getMessage(); 1373 | $trace = $e->getTraceAsString(); 1374 | foreach ($e->getTrace() as $call) { 1375 | $file = $call['file'] ?? 'Unknown'; 1376 | $line = $call['line'] ?? 0; 1377 | if ($file !== __FILE__) { 1378 | break; 1379 | } 1380 | } 1381 | echo "\nAssert failed: " . (empty($msg) ? '' : "{$msg} ") . "in {$file} on line {$line}\nStack trace: \n{$trace}\n"; 1382 | } 1383 | } 1384 | 1385 | private function __construct() 1386 | { 1387 | } 1388 | } 1389 | -------------------------------------------------------------------------------- /tests/include/lib/vendor/autoload.php: -------------------------------------------------------------------------------- 1 | $filename]; 45 | } else { 46 | $path = pathinfo($filename); 47 | } 48 | $path['dirname'] = trim($path['dirname'], './'); // i know arg2 is a list but it's no problem 49 | 50 | $replacement = []; 51 | $tip = rocksdb_color("[Test name]: ", ROCKSDB_COLOR_BLUE); 52 | $path['filename'] = fgetsin($tip, false);// use test name to be filename 53 | $tip = rocksdb_color("[Test intro]: ", ROCKSDB_COLOR_BLUE); 54 | $replacement['test_intro'] = fgetsin($tip, false); 55 | $this_dir_name = explode('/', $path['dirname']); 56 | $replacement['test_name'] = end($this_dir_name); // use dir name to be test name 57 | 58 | $filename = "{$path['dirname']}/{$path['filename']}.phpt"; 59 | 60 | //if dir not exist, create it 61 | if (!is_dir(__DIR__ . "/{$path['dirname']}")) { 62 | echo rocksdb_color( 63 | "The dir [{$path['dirname']}] is not exist, if you want to create it? [y/n]: ", 64 | ROCKSDB_COLOR_YELLOW 65 | ); 66 | if (yes()) { 67 | mkdir($path['dirname'], 0755, true); 68 | } else { 69 | exit(rocksdb_color('Can\'t generate the test file in nonexistent dir!', ROCKSDB_COLOR_RED)); 70 | } 71 | } elseif (file_exists($filename)) { 72 | echo rocksdb_color( 73 | "The file [{$path['filename']}] is exist, if you want to overwrite it? [y/n]: ", 74 | ROCKSDB_COLOR_YELLOW 75 | ); 76 | if (!yes()) { 77 | exit(rocksdb_color('You should rename your test filename.', ROCKSDB_COLOR_RED)); 78 | } 79 | } 80 | 81 | //calc dir deep 82 | $deep = 0; 83 | $temp = $filename; 84 | while (($temp = dirname($temp)) !== '.') { 85 | $deep++; 86 | } 87 | if ($deep < 1) { 88 | goto error_filename; 89 | } 90 | 91 | $template = file_get_contents(__DIR__ . '/template'); 92 | $replacement['dir_deep'] = str_repeat('/..', $deep); 93 | foreach ($replacement as $key => $value) { 94 | $template = str_replace("{{{$key}}}", $value, $template); 95 | } 96 | 97 | if (file_put_contents($filename, $template)) { 98 | echo rocksdb_color("Generate the test file successfully!\n", ROCKSDB_COLOR_GREEN) . 99 | "[" . __DIR__ . "/$filename]"; 100 | @shell_exec('/usr/bin/env git add ' . __DIR__ . "/$filename"); 101 | if (\stripos(PHP_OS, 'Darwin') !== false) { 102 | //MacOS 103 | $pstorm = '/usr/local/bin/pstorm'; 104 | if (file_exists($pstorm) || ( 105 | file_exists('/Applications/PhpStorm.app') && 106 | file_put_contents($pstorm, file_get_contents(__DIR__ . '/include/macos/phpstorm.py')) && 107 | chmod($pstorm, 0744) 108 | ) 109 | ) { 110 | @shell_exec("/usr/local/bin/phpstorm {$filename}"); 111 | } 112 | } 113 | } else { 114 | exit("\nGenerate the test file failed!"); 115 | } 116 | -------------------------------------------------------------------------------- /tests/rocksdb_db/close.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rocksdb_db: rocksdb close 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | open('tmp', ['create_if_missing' => true]); 15 | Assert::true($db->close()); 16 | Assert::true(RocksDB\DB::destroyDB('tmp')); 17 | ?> 18 | --EXPECT-- 19 | -------------------------------------------------------------------------------- /tests/rocksdb_db/del.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rocksdb_db: rocksdb del 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | open('tmp', ['create_if_missing' => true]); 15 | Assert::true($db->put('key', 'value')); 16 | Assert::true($db->del('key')); 17 | 18 | try { 19 | $db->get('key'); 20 | } catch (RocksDB\Exception $e) { 21 | Assert::eq($e->getMessage(), "NotFound: "); 22 | } 23 | 24 | Assert::true($db->close()); 25 | Assert::true(RocksDB\DB::destroyDB('tmp')); 26 | ?> 27 | --EXPECT-- -------------------------------------------------------------------------------- /tests/rocksdb_db/deleteRange.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rocksdb_db: rocksdb deleteRange 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | true, 15 | ]; 16 | 17 | $db = new RocksDB\DB(); 18 | $db->open('tmp', $option); 19 | Assert::true($db->put('key1', 'value1')); 20 | Assert::true($db->put('key2', 'value2')); 21 | Assert::true($db->put('key3', 'value3')); 22 | Assert::true($db->deleteRange('key1', 'key3')); 23 | 24 | Assert::eq($db->get('key3'), 'value3'); 25 | 26 | try { 27 | $ret = $db->get('key1'); 28 | $ret = $db->get('key2'); 29 | } catch (RocksDB\Exception $e) { 30 | Assert::eq($e->getMessage(), "NotFound: "); 31 | } 32 | 33 | Assert::true($db->close()); 34 | Assert::true(RocksDB\DB::destroyDB('tmp')); 35 | ?> 36 | --EXPECT-- 37 | -------------------------------------------------------------------------------- /tests/rocksdb_db/destroyDB.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rocksdb_db: rocksdb destroyDB 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | open('tmp', ['create_if_missing' => true]); 15 | Assert::true($db->close()); 16 | Assert::true(RocksDB\DB::destroyDB('tmp')); 17 | ?> 18 | --EXPECT-- 19 | -------------------------------------------------------------------------------- /tests/rocksdb_db/get.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rocksdb_db: rocksdb get 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | open('tmp', ['create_if_missing' => true]); 15 | $db->put('key', 'value'); 16 | Assert::eq($db->get('key'), 'value'); 17 | 18 | Assert::true($db->close()); 19 | Assert::true(RocksDB\DB::destroyDB('tmp')); 20 | ?> 21 | --EXPECT-- 22 | -------------------------------------------------------------------------------- /tests/rocksdb_db/iterator.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rocksdb_db: rocksdb iterator 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | true, 15 | ]; 16 | 17 | $db = new RocksDB\DB(); 18 | $db->open('tmp', $option); 19 | $db->put('key1', 'value1'); 20 | $db->put('key2', 'value2'); 21 | $db->put('key3', 'value3'); 22 | 23 | $ret = []; 24 | 25 | $iter = $db->newIterator('key1'); 26 | $i = 1; 27 | foreach ($iter as $key => $value) { 28 | Assert::eq($key, "key{$i}"); 29 | Assert::eq($value, "value{$i}"); 30 | $i++; 31 | } 32 | 33 | unset($iter); 34 | 35 | Assert::true($db->close()); 36 | Assert::true(RocksDB\DB::destroyDB('tmp')); 37 | ?> 38 | --EXPECT-- -------------------------------------------------------------------------------- /tests/rocksdb_db/keyExist.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rocksdb_db: keyExist 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | true, 17 | ]; 18 | 19 | $db = new RocksDB\DB($path, $option); 20 | $db->open($path, $option); 21 | 22 | Assert::false($db->keyExist('nonexistent')); 23 | 24 | $db->put('key', 'value'); 25 | Assert::true($db->keyExist('key')); 26 | 27 | Assert::true($db->close()); 28 | Assert::true(RocksDB\DB::destroyDB($path)); 29 | ?> 30 | --EXPECT-- 31 | -------------------------------------------------------------------------------- /tests/rocksdb_db/keyMayExist.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rocksdb_db: keyMayExist 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | true, 17 | ]; 18 | 19 | $db = new RocksDB\DB($path, $option); 20 | 21 | $db->open($path, $option); 22 | 23 | Assert::false($db->keyMayExist('nonexistent')); 24 | 25 | Assert::true($db->close()); 26 | Assert::true(RocksDB\DB::destroyDB($path)); 27 | ?> 28 | --EXPECT-- 29 | -------------------------------------------------------------------------------- /tests/rocksdb_db/open.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rocksdb_db: rocksdb open 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | 16 | --EXPECT-- -------------------------------------------------------------------------------- /tests/rocksdb_db/open_read_only.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rocksdb_db: open rocksdb read only 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | open('tmp', ['create_if_missing' => true]); 15 | try { 16 | $db->put('key1', 'value1'); 17 | 18 | } catch (RocksDB\Exception $e) { 19 | Assert::eq($e->getMessage(), 'Not implemented: Not supported operation in read only mode.'); 20 | } 21 | 22 | Assert::true($db->close()); 23 | Assert::true(RocksDB\DB::destroyDB('tmp')); 24 | ?> 25 | --EXPECT-- 26 | -------------------------------------------------------------------------------- /tests/rocksdb_db/put.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rocksdb_db: rocksdb put 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | open('tmp', ['create_if_missing' => true]); 15 | Assert::true($db->put('key', 'value')); 16 | 17 | Assert::true($db->close()); 18 | Assert::true(RocksDB\DB::destroyDB('tmp')); 19 | ?> 20 | --EXPECT-- 21 | -------------------------------------------------------------------------------- /tests/rocksdb_db/write.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rocksdb_db: rocksdb write 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | open('tmp', ['create_if_missing' => true]); 15 | 16 | $batch = new RocksDB\WriteBatch(); 17 | $batch->put('key', 'value'); 18 | $batch->delete('key'); 19 | 20 | $db->write($batch); 21 | 22 | try { 23 | $db->get('key'); 24 | } catch (RocksDB\Exception $e) { 25 | Assert::eq($e->getMessage(), "NotFound: "); 26 | } 27 | 28 | Assert::true($db->close()); 29 | Assert::true(RocksDB\DB::destroyDB('tmp')); 30 | ?> 31 | --EXPECT-- 32 | -------------------------------------------------------------------------------- /tests/rocksdb_exception/throw_rocksdb_exception.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rocksdb_exception: throw RocksDB\Exception 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | getMessage(), 'RocksDB exception'); 17 | } 18 | ?> 19 | --EXPECT-- -------------------------------------------------------------------------------- /tests/rocksdb_transaction_db/commit.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rocksdb_transaction_db: commit 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | true, 15 | ]; 16 | 17 | $db = new RocksDB\TransactionDB(); 18 | $db->open('tmp', $option); 19 | Assert::true($db->put('key', 'value')); 20 | Assert::eq($db->get('key'), 'value'); 21 | $transaction = $db->beginTransaction([], ['set_snapshot' => true]); 22 | Assert::true($transaction->put('key', 'value1')); 23 | Assert::eq($transaction->get('key'), 'value1'); 24 | Assert::eq($db->get('key'), 'value'); 25 | Assert::true($transaction->commit()); 26 | Assert::eq($db->get('key'), 'value1'); 27 | 28 | Assert::true($db->close()); 29 | Assert::true(RocksDB\DB::destroyDB('tmp')); 30 | ?> 31 | --EXPECT-- 32 | -------------------------------------------------------------------------------- /tests/rocksdb_transaction_db/snapshot.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | rocksdb_transaction_db: snapshot 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | true, 15 | ]; 16 | 17 | $db = new RocksDB\TransactionDB(); 18 | $db->open('tmp', $option); 19 | $db->put('key', 'value'); 20 | Assert::eq($db->get('key'), 'value'); 21 | $transaction = $db->beginTransaction([], ['set_snapshot' => true]); 22 | $snapshot = $transaction->getSnapshot(); 23 | $db->put('key', 'value1'); 24 | Assert::eq($db->get('key'), 'value1'); 25 | Assert::eq($db->Get("key", ['snapshot' => $snapshot]), 'value'); 26 | 27 | Assert::true($db->close()); 28 | Assert::true(RocksDB\DB::destroyDB('tmp')); 29 | ?> 30 | --EXPECT-- 31 | -------------------------------------------------------------------------------- /tests/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | __CURRENT__=`pwd` 3 | __DIR__=$(cd "$(dirname "$0")";pwd) 4 | 5 | clear_php() 6 | { 7 | ps -A | grep \.php$ | grep -v phpstorm | grep -v php-fpm | awk '{print $1}' | xargs kill -9 > /dev/null 2>&1 8 | } 9 | 10 | ## before tests 11 | clear_php 12 | if [ `ulimit -n` -le 16384 ]; then 13 | ulimit -n 16384 > /dev/null 2>&1 14 | fi 15 | # run tests 16 | if [ -z "${TEST_PHP_EXECUTABLE}" ]; then 17 | export TEST_PHP_EXECUTABLE=`which php` 18 | fi 19 | 20 | if [ -z "${1}" ]; then 21 | glob="rocksdb_*" 22 | else 23 | if [ "${1}x" = "basex" ]; then 24 | glob="\ 25 | rocksdb_db" 26 | if [ ${#} -gt 1 ]; then 27 | args="${@}" 28 | args="${args#* }" 29 | glob="${args} ${glob}" 30 | fi 31 | else 32 | glob="$@" 33 | fi 34 | fi 35 | 36 | if [ $? -eq 0 ]; then 37 | PHPT=1 ${TEST_PHP_EXECUTABLE} -d "memory_limit=1024m" ${__DIR__}/run-tests ${glob} 38 | fi 39 | 40 | # after tests 41 | clear_php 42 | rm -f /tmp/rocksdb.log > /dev/null 2>&1 43 | -------------------------------------------------------------------------------- /tests/template: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | {{test_name}}: {{test_intro}} 3 | --SKIPIF-- 4 | 9 | --FILE-- 10 | true, 17 | ]; 18 | 19 | $db = new RocksDB\DB($path, $option); 20 | $db->open($path, $option); 21 | 22 | Assert::true($db->close()); 23 | Assert::true(RocksDB\DB::destroyDB($path)); 24 | ?> 25 | --EXPECT-- 26 | --------------------------------------------------------------------------------