You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by is...@apache.org on 2018/10/09 14:47:30 UTC

[15/21] ignite git commit: IGNITE-7783: PHP thin client

http://git-wip-us.apache.org/repos/asf/ignite/blob/f28e4f3f/modules/platforms/php/src/Apache/Ignite/Type/CollectionObjectType.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Type/CollectionObjectType.php b/modules/platforms/php/src/Apache/Ignite/Type/CollectionObjectType.php
new file mode 100644
index 0000000..b9591cb
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Type/CollectionObjectType.php
@@ -0,0 +1,142 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Type;
+
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Internal\Utils\ArgumentChecker;
+use Apache\Ignite\Internal\Binary\BinaryUtils;
+
+/** 
+ * Class representing a collection type of Ignite object.
+ * 
+ * It is described by ObjectType::COLLECTION and one of @ref CollectionSubType.
+ */
+class CollectionObjectType extends ObjectType
+{
+    /** @name CollectionSubType
+     *  @anchor CollectionSubType
+     *  @{
+     */
+    
+    /**
+     * General set type, which can not be mapped to more specific set type.
+     */
+    const USER_SET = -1;
+    
+    /**
+     * General collection type, which can not be mapped to any specific collection type.
+     */
+    const USER_COL = 0;
+    
+    /**
+     * Resizeable array type.
+     */
+    const ARRAY_LIST = 1;
+    
+    /**
+     * Linked list type.
+     */
+    const LINKED_LIST = 2;
+    
+    /**
+     * Basic hash set type.
+     */
+    const HASH_SET = 3;
+    
+    /**
+     * Hash set type, which maintains element order.
+     */
+    const LINKED_HASH_SET = 4;
+    
+    /**
+     * This is a collection that only contains a single element, but behaves as a collection.
+     */
+    const SINGLETON_LIST = 5;
+
+    /** @} */ // end of CollectionSubType
+
+    private $subType;
+    private $elementType;
+    
+    /**
+     * Public constructor.
+     *
+     * Specifies the collection subtype and optionally specifies Ignite type of elements in the collection.
+     *
+     * If Ignite type of elements is not specified then during operations the Ignite client
+     * tries to make automatic mapping between PHP types and Ignite object types -
+     * according to the mapping table defined in the description of the ObjectType class.
+     * 
+     * @param int $subType collection subtype, one of @ref CollectionSubType constants.
+     * @param int|ObjectType|null $elementType Ignite type of elements in the collection:
+     *   - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+     *   - or an instance of class representing non-primitive (composite) type
+     *   - or null (or not specified) that means the type is not specified
+     * 
+     * @throws ClientException if error.
+     */
+    public function __construct(int $subType, $elementType = null)
+    {
+        parent::__construct(ObjectType::COLLECTION);
+        ArgumentChecker::hasValueFrom(
+            $subType, 'subType', false, 
+            [
+                CollectionObjectType::USER_SET,
+                CollectionObjectType::USER_COL,
+                CollectionObjectType::ARRAY_LIST,
+                CollectionObjectType::LINKED_LIST,
+                CollectionObjectType::HASH_SET,
+                CollectionObjectType::LINKED_HASH_SET,
+                CollectionObjectType::SINGLETON_LIST
+            ]);
+        BinaryUtils::checkObjectType($elementType, 'elementType');
+        $this->subType = $subType;
+        $this->elementType = $elementType;
+    }
+
+    /**
+     * Returns collection subtype, one of @ref CollectionSubType constants.
+     * 
+     * @return int collection subtype, one of @ref CollectionSubType constants.
+     */
+    public function getSubType(): int
+    {
+        return $this->subType;
+    }
+    
+    /**
+     * Returns Ignite type of elements in the collection.
+     * 
+     * @return int|ObjectType|null type of elements in the collection:
+     *   - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+     *   - or an instance of class representing non-primitive (composite) type
+     *   - or null that means the type is not specified
+     */
+    public function getElementType()
+    {
+        return $this->elementType;
+    }
+    
+    public static function isSet($subType): bool
+    {
+        return $subType === CollectionObjectType::USER_SET ||
+            $subType === CollectionObjectType::HASH_SET ||
+            $subType === CollectionObjectType::LINKED_HASH_SET;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/f28e4f3f/modules/platforms/php/src/Apache/Ignite/Type/ComplexObjectType.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Type/ComplexObjectType.php b/modules/platforms/php/src/Apache/Ignite/Type/ComplexObjectType.php
new file mode 100644
index 0000000..b62272e
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Type/ComplexObjectType.php
@@ -0,0 +1,165 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Type;
+
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Internal\Binary\BinaryUtils;
+
+/**
+ * Class representing a complex type of Ignite object.
+ *
+ * It corresponds to the ObjectType::COMPLEX_OBJECT Ignite type code.
+ *
+ * This class may be needed to help Ignite client to:
+ *   - deserialize an Ignite complex object to a PHP object when reading data,
+ *   - serialize a PHP object to an Ignite complex object when writing data.
+ *
+ * Note: only public properties of PHP objects can be serialized/deserialized.
+ */
+class ComplexObjectType extends ObjectType
+{
+    private $phpClassName;
+    private $typeName;
+    private $fieldTypes;
+    
+    /**
+     * Public constructor.
+     *
+     * Creates a default representation of Ignite complex object type.
+     * setPhpClassName(), setIgniteTypeName(), setFieldType() methods may be used
+     * to change the default representation.
+     */
+    public function __construct()
+    {
+        parent::__construct(ObjectType::COMPLEX_OBJECT);
+        $this->phpClassName = null;
+        $this->typeName = null;
+        $this->fieldTypes = [];
+    }
+    
+    /**
+     * Sets the name of the PHP class.
+     *
+     * Affects data reading operations only.
+     *
+     * The specified name will be used as PHP class name to instantiate a PHP object
+     * the received Ignite complex object is deserialized to.
+     *
+     * By default (if the name is not specified), the Ignite complex type name of the received complex object
+     * is used as PHP class name to instantiate a PHP object during deserialization.
+     *
+     * The PHP Class must have a constructor without parameters or with optional parameters only.
+     *
+     * @param string|null $phpClassName name of the PHP class or null (the name is not specified).
+     * 
+     * @return ComplexObjectType the same instance of the ComplexObjectType.
+     */
+    public function setPhpClassName(?string $phpClassName): ComplexObjectType
+    {
+        $this->phpClassName = $phpClassName;
+        return $this;
+    }
+    
+    /**
+     * Gets the name of the PHP class.
+     *
+     * @return string|null name of the PHP class or null (the name is not specified).
+     */
+    public function getPhpClassName(): ?string
+    {
+        return $this->phpClassName;
+    }
+    
+    /**
+     * Sets the name of the Ignite complex type.
+     *
+     * Affects data writing operations only.
+     *
+     * The specified name will be used as the Ignite complex type name during the complex object's writing operations.
+     *
+     * By default (if the name is not specified), the Ignite complex type name of the serialized complex object
+     * is taken from the name of the PHP class which instance is provided in a data writing operation.
+     *
+     * @param string|null $typeName name of the Ignite complex type or null (the name is not specified).
+     * 
+     * @return ComplexObjectType the same instance of the ComplexObjectType.
+     */
+    public function setIgniteTypeName(?string $typeName): ComplexObjectType
+    {
+        $this->typeName = $typeName;
+        return $this;
+    }
+
+    /**
+     * Gets the name of the Ignite complex type.
+     * 
+     * @return string|null name of the Ignite complex type or null (the name is not specified).
+     */
+    public function getIgniteTypeName(): ?string
+    {
+        return $this->typeName;
+    }
+
+    /**
+     * Specifies Ignite type of the indicated field in the complex type.
+     *
+     * Affects data writing operations only.
+     *
+     * During data serialization Ignite client will assume that the indicated field
+     * has the Ignite type specified by this method.
+     *
+     * By default (if the type of the field is not specified),
+     * Ignite client tries to make automatic mapping between PHP types and Ignite object types -
+     * according to the mapping table defined in the description of the ObjectType class.
+     * 
+     * @param string $fieldName name of the field.
+     * @param int|ObjectType|null $fieldType Ignite type of the field:
+     *   - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+     *   - or an instance of class representing non-primitive (composite) type
+     *   - or null (or not specified) that means the type is not specified
+     *
+     * @return ComplexObjectType the same instance of the ComplexObjectType.
+     *
+     * @throws ClientException if error.
+     */
+    public function setFieldType(string $fieldName, $fieldType): ComplexObjectType
+    {
+        BinaryUtils::checkObjectType($fieldType, 'fieldType');
+        $this->fieldTypes[$fieldName] = $fieldType;
+        return $this;
+    }
+
+    /**
+     * Gets Ignite type of the indicated field in the complex type.
+     *
+     * @param string $fieldName name of the field.
+     *
+     * @return int|ObjectType|null Ignite type of the field:
+     *   - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+     *   - or an instance of class representing non-primitive (composite) type
+     *   - or null that means the type is not specified
+     */
+    public function getFieldType(string $fieldName)
+    {
+        if (array_key_exists($fieldName, $this->fieldTypes)) {
+            return $this->fieldTypes[$fieldName];
+        }
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/f28e4f3f/modules/platforms/php/src/Apache/Ignite/Type/MapObjectType.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Type/MapObjectType.php b/modules/platforms/php/src/Apache/Ignite/Type/MapObjectType.php
new file mode 100644
index 0000000..043ae6a
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Type/MapObjectType.php
@@ -0,0 +1,123 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Type;
+
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Internal\Utils\ArgumentChecker;
+use Apache\Ignite\Internal\Binary\BinaryUtils;
+
+/** 
+ * Class representing a map type of Ignite object.
+ * 
+ * It is described by ObjectType::MAP and one of @ref MapSubType.
+ */
+class MapObjectType extends ObjectType
+{
+    /** @name MapSubType
+     *  @anchor MapSubType
+     *  @{
+     */
+
+    /**
+     * Basic hash map.
+     */
+    const HASH_MAP = 1;
+    
+    /**
+     * Hash map, which maintains element order.
+     */
+    const LINKED_HASH_MAP = 2;
+    
+    /** @} */ // end of MapSubType
+    
+    private $subType;
+    private $keyType;
+    private $valueType;
+
+    /**
+     * Public constructor.
+     *
+     * Optionally specifies the map subtype and Ignite types of keys and values in the map.
+     *
+     * If the map subtype is not specified, MapObjectType::HASH_MAP is assumed.
+     *
+     * If Ignite type is not specified for the key and/or value then during operations the Ignite client
+     * tries to make automatic mapping between PHP types and Ignite object types -
+     * according to the mapping table defined in the description of the ObjectType class.
+     * 
+     * @param int $subType map subtype, one of @ref MapSubType constants.
+     * @param int|ObjectType|null $keyType Ignite type of the keys in the map:
+     *   - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+     *   - or an instance of class representing non-primitive (composite) type
+     *   - or null (or not specified) that means the type is not specified
+     * @param int|ObjectType|null $valueType Ignite type of the values in the map:
+     *   - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+     *   - or an instance of class representing non-primitive (composite) type
+     *   - or null (or not specified) that means the type is not specified
+     * 
+     * @throws ClientException if error.
+     */
+    public function __construct(int $subType = MapObjectType::HASH_MAP, $keyType = null, $valueType = null)
+    {
+        parent::__construct(ObjectType::MAP);
+        ArgumentChecker::hasValueFrom(
+            $subType, 'subType', false, [MapObjectType::HASH_MAP, MapObjectType::LINKED_HASH_MAP]);
+        BinaryUtils::checkObjectType($keyType, 'keyType');
+        BinaryUtils::checkObjectType($valueType, 'valueType');
+        $this->subType = $subType;
+        $this->keyType = $keyType;
+        $this->valueType = $valueType;
+    }
+
+    /**
+     * Returns the map subtype, one of @ref MapSubType constants.
+     * 
+     * @return int map subtype, one of @ref MapSubType constants.
+     */
+    public function getSubType(): int
+    {
+        return $this->subType;
+    }
+    
+    /**
+     * Returns Ignite type of the keys in the map.
+     * 
+     * @return int|ObjectType|null type of the keys in the map:
+     *   - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+     *   - or an instance of class representing non-primitive (composite) type
+     *   - or null that means the type is not specified
+     */
+    public function getKeyType()
+    {
+        return $this->keyType;
+    }
+
+    /**
+     * Returns Ignite type of the values in the map.
+     * 
+     * @return int|ObjectType|null type of the values in the map:
+     *   - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+     *   - or an instance of class representing non-primitive (composite) type
+     *   - or null that means the type is not specified
+     */
+    public function getValueType()
+    {
+        return $this->valueType;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/f28e4f3f/modules/platforms/php/src/Apache/Ignite/Type/ObjectArrayType.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Type/ObjectArrayType.php b/modules/platforms/php/src/Apache/Ignite/Type/ObjectArrayType.php
new file mode 100644
index 0000000..89c8eca
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Type/ObjectArrayType.php
@@ -0,0 +1,68 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Type;
+
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Internal\Binary\BinaryUtils;
+
+/**
+ * Class representing an array type of Ignite objects.
+ *
+ * It is described by ObjectType::OBJECT_ARRAY.
+ */
+class ObjectArrayType extends ObjectType
+{
+    private $elementType;
+    
+    /**
+     * Public constructor.
+     *
+     * Optionally specifies Ignite type of elements in the array.
+     *
+     * If Ignite type of elements is not specified then during operations the Ignite client
+     * tries to make automatic mapping between PHP types and Ignite object types -
+     * according to the mapping table defined in the description of the ObjectType class.
+     * 
+     * @param int|ObjectType|null $elementType Ignite type of the array element:
+     *   - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+     *   - or an instance of class representing non-primitive (composite) type
+     *   - or null (or not specified) that means the type is not specified
+     * 
+     * @throws ClientException if error.
+     */
+    public function __construct($elementType = null)
+    {
+        parent::__construct(ObjectType::OBJECT_ARRAY);
+        BinaryUtils::checkObjectType($elementType, 'elementType');
+        $this->elementType = $elementType;
+    }
+    
+    /**
+     * Returns Ignite type of the array element.
+     * 
+     * @return int|ObjectType|null Ignite type of the array element:
+     *   - either a type code of primitive (simple) type (@ref PrimitiveTypeCodes)
+     *   - or an instance of class representing non-primitive (composite) type
+     *   - or null that means the type is not specified
+     */
+    public function getElementType()
+    {
+        return $this->elementType;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/f28e4f3f/modules/platforms/php/src/Apache/Ignite/Type/ObjectType.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/src/Apache/Ignite/Type/ObjectType.php b/modules/platforms/php/src/Apache/Ignite/Type/ObjectType.php
new file mode 100644
index 0000000..c91d120
--- /dev/null
+++ b/modules/platforms/php/src/Apache/Ignite/Type/ObjectType.php
@@ -0,0 +1,442 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Type;
+
+/** 
+ * Base class representing a type of Ignite object.
+ * 
+ * The class is abstract and has no public constructor. Only subclasses may be instantiated.
+ *
+ * There are two groups of Ignite object types:
+ *
+ * - Primitive (simple) types. To fully describe such a type:
+ * it is enough to specify Ignite type code @ref PrimitiveTypeCodes only.
+ *
+ * - Non-primitive (composite) types. To fully describe such a type:
+ * Ignite type code @ref CompositeTypeCodes with additional information
+ * (eg. a kind of map or a kind of collection) should be specified.
+ *
+ * This class helps the Ignite client to make a mapping between PHP types
+ * and types used by Ignite according to the following mapping tables:
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * COMMENTS TO ALL TABLES
+ * ----------------
+ *
+ * PHP type
+ * ----------------
+ * It is a PHP primitive or a PHP object: http://php.net/manual/en/language.types.intro.php
+ *
+ * Associative and indexed PHP arrays: http://php.net/manual/en/language.types.array.php
+ *
+ * Additional types:
+ *   - Ds\\Set, Ds\\Map - PHP Data Structures extension classes: http://php.net/manual/en/book.ds.php
+ *   - Brick\\Math\\BigDecimal - PHP class from the extension library
+ *                               to work with arbitrary precision numbers: https://github.com/brick/math
+ *   - Date, Time, Timestamp, EnumItem, BinaryObject - PHP classes introduced by the Ignite client.
+ *
+ * Ignite type code
+ * ----------------
+ * It is a type code of Ignite primitive type (@ref PrimitiveTypeCodes)
+ * or Ignite composite type (@ref CompositeTypeCodes).
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * MAPPING FROM IGNITE TYPE CODE TO PHP TYPE WHEN READING DATA
+ * ----------------
+ *
+ * | Ignite type code             | PHP type                                      |
+ * | ---------------------------- | ----------------------------------------------|
+ * | BYTE                         | integer                                       |
+ * | SHORT                        | integer                                       |
+ * | INTEGER                      | integer                                       |
+ * | LONG                         | float                                         |
+ * | FLOAT                        | float                                         |
+ * | DOUBLE                       | float                                         |
+ * | DECIMAL                      | Brick\\Math\\BigDecimal                       |
+ * | BOOLEAN                      | boolean                                       |
+ * | STRING                       | string                                        |
+ * | CHAR                         | string (one character)                        |
+ * | UUID                         | indexed array of integers (16 items)          |
+ * | DATE                         | Date                                          |
+ * | TIME                         | Time                                          |
+ * | TIMESTAMP                    | Timestamp                                     |
+ * | ENUM                         | EnumItem                                      |
+ * | COMPLEX_OBJECT               | BinaryObject or PHP object*                   |
+ * | BYTE_ARRAY                   | indexed array of integer                      |
+ * | SHORT_ARRAY                  | indexed array of integer                      |
+ * | INTEGER_ARRAY                | indexed array of integer                      |
+ * | LONG_ARRAY                   | indexed array of float                        |
+ * | FLOAT_ARRAY                  | indexed array of float                        |
+ * | DOUBLE_ARRAY                 | indexed array of float                        |
+ * | DECIMAL_ARRAY                | indexed array of Brick\\Math\\BigDecimal      |
+ * | BOOLEAN_ARRAY                | indexed array of boolean                      |
+ * | STRING_ARRAY                 | indexed array of string                       |
+ * | CHAR_ARRAY                   | indexed array of string (one character)       |
+ * | UUID_ARRAY                   | indexed array of array of integers (16 items) |
+ * | DATE_ARRAY                   | indexed array of Date                         |
+ * | TIME_ARRAY                   | indexed array of Time                         |
+ * | TIMESTAMP_ARRAY              | indexed array of Timestamp                    |
+ * | ENUM_ARRAY                   | indexed array of EnumItem                     |
+ * | OBJECT_ARRAY                 | indexed array                                 |
+ * | COLLECTION (USER_COL)        | indexed array                                 |
+ * | COLLECTION (ARR_LIST)        | indexed array                                 |
+ * | COLLECTION (LINKED_LIST)     | indexed array                                 |
+ * | COLLECTION (SINGLETON_LIST)  | indexed array                                 |
+ * | COLLECTION (HASH_SET)        | Ds\\Set                                       |
+ * | COLLECTION (LINKED_HASH_SET) | Ds\\Set                                       |
+ * | COLLECTION (USER_SET)        | Ds\\Set                                       |
+ * | MAP (HASH_MAP)               | Ds\\Map                                       |
+ * | MAP (LINKED_HASH_MAP)        | Ds\\Map                                       |
+ * | NULL                         | null**                                        |
+ *
+ * (*) If an application does not explicitly specify an Ignite type for a field and
+ * COMPLEX_OBJECT is received, the Ignite client returns BinaryObject to the application.
+ * If an application explicitly specifies ComplexObjectType for a field,
+ * the Ignite client deserializes the received COMPLEX_OBJECT into PHP object
+ * specified by the ComplexObjectType.
+ *
+ * (**) NULL cannot be specified as an Ignite type of a field but PHP null may be returned
+ * as a value of a field.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * DEFAULT MAPPING FROM PHP TYPE TO IGNITE TYPE CODE WHEN WRITING DATA
+ * ----------------
+ *
+ * This mapping is used when an application does not explicitly specify an Ignite type
+ * for a field and it is writing data to that field.
+ *
+ * | PHP type                                    | Ignite type code      |
+ * | ------------------------------------------- | ----------------------|
+ * | boolean                                     | BOOLEAN               |
+ * | integer                                     | INTEGER               |
+ * | float                                       | DOUBLE                |
+ * | string                                      | STRING                |
+ * | Date                                        | DATE                  |
+ * | Time                                        | TIME                  |
+ * | Timestamp                                   | TIMESTAMP             |
+ * | EnumItem                                    | ENUM                  |
+ * | Brick\\Math\\BigDecimal                     | DECIMAL               |
+ * | BinaryObject                                | COMPLEX_OBJECT        |
+ * | any other PHP Object*                       | COMPLEX_OBJECT        |
+ * | associative array of PHP supported type**   | MAP (HASH_MAP)        |
+ * | indexed array of boolean***                 | BOOLEAN_ARRAY         |
+ * | indexed array of integer                    | INTEGER_ARRAY         |
+ * | indexed array of float                      | DOUBLE_ARRAY          |
+ * | indexed array of string                     | STRING_ARRAY          |
+ * | indexed array of Date                       | DATE_ARRAY            |
+ * | indexed array of Time                       | TIME_ARRAY            |
+ * | indexed array of Timestamp                  | TIMESTAMP_ARRAY       |
+ * | indexed array of EnumItem                   | ENUM_ARRAY            |
+ * | indexed array of Brick\\Math\\BigDecimal    | DECIMAL_ARRAY         |
+ * | indexed array of BinaryObject               | OBJECT_ARRAY          |
+ * | indexed array of any other PHP Object*      | OBJECT_ARRAY          |
+ * | Ds\\Set                                     | COLLECTION (HASH_SET) |
+ * | Ds\\Map                                     | MAP (HASH_MAP)        |
+ *
+ * All other PHP types have no default mapping to Ignite type codes.
+ *
+ * (*) Any other PHP Object - is any PHP class, not explicitly mentioned in the table.
+ *
+ * (**) PHP supported type - is any PHP type mentioned in the table.
+ * 
+ * (***) Type of an indexed array's value is determined by the value's type in the first element of the array.
+ * Empty array has no default mapping.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * ALLOWED PHP TYPES WHEN WRITING DATA OF THE SPECIFIED IGNITE TYPE CODE
+ * ----------------
+ *
+ * When an application explicitly specifies an Ignite type for a field
+ * and it is writing data to that field, the following PHP types
+ * are allowed for every concrete Ignite type code.
+ *
+ * | Specified Ignite type code   | Allowed PHP types                             |
+ * | ---------------------------- | ----------------------------------------------|
+ * | BYTE                         | integer                                       |
+ * | SHORT                        | integer                                       |
+ * | INTEGER                      | integer                                       |
+ * | LONG                         | float, integer                                |
+ * | FLOAT                        | float, integer                                |
+ * | DOUBLE                       | float, integer                                |
+ * | DECIMAL                      | Brick\\Math\\BigDecimal                       |
+ * | BOOLEAN                      | boolean                                       |
+ * | STRING                       | string                                        |
+ * | CHAR                         | string (one character)                        |
+ * | UUID                         | indexed array of integers (16 items)          |
+ * | DATE                         | Date                                          |
+ * | TIME                         | Time                                          |
+ * | TIMESTAMP                    | Timestamp                                     |
+ * | ENUM                         | EnumItem                                      |
+ * | COMPLEX_OBJECT               | BinaryObject, any PHP object                  |
+ * | BYTE_ARRAY*                  | indexed array of integer                      |
+ * | SHORT_ARRAY                  | indexed array of integer                      |
+ * | INTEGER_ARRAY                | indexed array of integer                      |
+ * | LONG_ARRAY                   | indexed array of float/integer                |
+ * | FLOAT_ARRAY                  | indexed array of float/integer                |
+ * | DOUBLE_ARRAY                 | indexed array of float/integer                |
+ * | DECIMAL_ARRAY                | indexed array of Brick\\Math\\BigDecimal      |
+ * | BOOLEAN_ARRAY                | indexed array of boolean                      |
+ * | STRING_ARRAY                 | indexed array of string                       |
+ * | CHAR_ARRAY                   | indexed array of string (one character)       |
+ * | UUID_ARRAY                   | indexed array of array of integers (16 items) |
+ * | DATE_ARRAY                   | indexed array of Date                         |
+ * | TIME_ARRAY                   | indexed array of Time                         |
+ * | TIMESTAMP_ARRAY              | indexed array of Timestamp                    |
+ * | ENUM_ARRAY                   | indexed array of EnumItem                     |
+ * | OBJECT_ARRAY                 | indexed array                                 |
+ * | COLLECTION (USER_COL)        | indexed array                                 |
+ * | COLLECTION (ARR_LIST)        | indexed array                                 |
+ * | COLLECTION (LINKED_LIST)     | indexed array                                 |
+ * | COLLECTION (SINGLETON_LIST)  | indexed array                                 |
+ * | COLLECTION (HASH_SET)        | Ds\\Set                                       |
+ * | COLLECTION (LINKED_HASH_SET) | Ds\\Set                                       |
+ * | COLLECTION (USER_SET)        | Ds\\Set                                       |
+ * | MAP (HASH_MAP)               | Ds\\Map, associative array                    |
+ * | MAP (LINKED_HASH_MAP)        | Ds\\Map, associative array                    |
+ *
+ * (*) For all *_ARRAY Ignite types an empty PHP indexed array is allowed.
+ *
+ * PHP null is allowed as value of a field (but not as a key/value in a cache)
+ * or as a value of Array/Set/Map element for all Ignite types,
+ * except BYTE, SHORT, INTEGER, LONG, FLOAT, DOUBLE, CHAR, BOOLEAN.
+ *
+ * ----------------------------------------------------------------------------
+ * 
+ */
+abstract class ObjectType
+{
+    /** @name PrimitiveTypeCodes
+     *  @anchor PrimitiveTypeCodes
+     *  @{
+     */
+    
+    /**
+     * Single byte value. Can also represent small signed integer value.
+     */
+    const BYTE = 1;
+    
+    /**
+     * 2-bytes long signed integer number.
+     */
+    const SHORT = 2;
+    
+    /**
+     * 4-bytes long signed integer number.
+     */
+    const INTEGER = 3;
+    
+    /**
+     * 8-bytes long signed integer number.
+     */
+    const LONG = 4;
+    
+    /**
+     * 4-byte long floating-point number.
+     */
+    const FLOAT = 5;
+
+    /**
+     * 8-byte long floating-point number.
+     */
+    const DOUBLE = 6;
+    
+    /**
+     * Single UTF-16 code unit.
+     */
+    const CHAR = 7;
+    
+    /**
+     * Boolean value.
+     */
+    const BOOLEAN = 8;
+    
+    /**
+     * String in UTF-8 encoding.
+     */
+    const STRING = 9;
+    
+    /**
+     * A universally unique identifier (UUID) is a 128-bit number used to identify information in computer systems.
+     */
+    const UUID = 10;
+    
+    /**
+     * Date, represented as a number of milliseconds elapsed since 00:00:00 1 Jan 1970 UTC.
+     */
+    const DATE = 11;
+    
+    /**
+     * Array of bytes.
+     */
+    const BYTE_ARRAY = 12;
+    
+    /**
+     * Array of short signed integer numbers.
+     */
+    const SHORT_ARRAY = 13;
+    
+    /**
+     * Array of signed integer numbers.
+     */
+    const INTEGER_ARRAY = 14;
+    
+    /**
+     * Array of long signed integer numbers.
+     */
+    const LONG_ARRAY = 15;
+    
+    /**
+     * Array of floating point numbers.
+     */
+    const FLOAT_ARRAY = 16;
+    
+    /**
+     * Array of floating point numbers with double precision.
+     */
+    const DOUBLE_ARRAY = 17;
+    
+    /**
+     * Array of UTF-16 code units.
+     */
+    const CHAR_ARRAY = 18;
+    
+    /**
+     * Array of boolean values.
+     */
+    const BOOLEAN_ARRAY = 19;
+    
+    /**
+     * Array of UTF-8 string values.
+     */
+    const STRING_ARRAY = 20;
+    
+    /**
+     * Array of UUIDs.
+     */
+    const UUID_ARRAY = 21;
+    
+    /**
+     * Array of dates.
+     */
+    const DATE_ARRAY = 22;
+    
+    /**
+     * Value of an enumerable type. For such types defined only a finite number of named values.
+     */
+    const ENUM = 28;
+    
+    /**
+     * Array of enumerable type value.
+     */
+    const ENUM_ARRAY = 29;
+    
+    /**
+     * Numeric value of any desired precision and scale.
+     */
+    const DECIMAL = 30;
+    
+    /**
+     * Array of decimal values.
+     */
+    const DECIMAL_ARRAY = 31;
+    
+    /**
+     * More precise than a Date data type. Except for a milliseconds since epoch, contains a nanoseconds
+     * fraction of a last millisecond, which value could be in a range from 0 to 999999. 
+     */
+    const TIMESTAMP = 33;
+    
+    /**
+     * Array of timestamp values.
+     */
+    const TIMESTAMP_ARRAY = 34;
+    
+    /**
+     * Time, represented as a number of milliseconds elapsed since midnight, i.e. 00:00:00 UTC.
+     */
+    const TIME = 36;
+    
+    /**
+     * Array of time values.
+     */
+    const TIME_ARRAY = 37;
+    /** @} */ // end of PrimitiveTypeCodes
+
+    /** @name CompositeTypeCodes
+     *  @anchor CompositeTypeCodes
+     *  @{
+     */
+    /**
+     * Array of objects of any type.
+     */
+    const OBJECT_ARRAY = 23;
+    
+    /**
+     * General collection type.
+     */
+    const COLLECTION = 24;
+    
+    /**
+     * Map-like collection type. Contains pairs of key and value objects.
+     */
+    const MAP = 25;
+    
+    /**
+     * Wrapped binary object type.
+     */
+    const BINARY_OBJECT = 27;
+    
+    /**
+     * Wrapped enumerable type.
+     */
+    const BINARY_ENUM = 38;
+    
+    /**
+     * null value.
+     */
+    const NULL = 101;
+
+    /**
+     * Complex object.
+     */
+    const COMPLEX_OBJECT = 103;
+    /** @} */ // end of CompositeTypeCodes
+    
+    private $typeCode;
+    
+    /**
+     * Gets Ignite type code of this Ignite object type.
+     * 
+     * @return int Ignite type code
+     */
+    public function getTypeCode(): int
+    {
+        return $this->typeCode;
+    }
+
+    //The class is abstract and has no public constructor. Only subclasses may be instantiated.
+    protected function __construct(int $typeCode)
+    {
+        $this->typeCode = $typeCode;
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/f28e4f3f/modules/platforms/php/tests/BinaryObjectTest.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/tests/BinaryObjectTest.php b/modules/platforms/php/tests/BinaryObjectTest.php
new file mode 100644
index 0000000..c5ca517
--- /dev/null
+++ b/modules/platforms/php/tests/BinaryObjectTest.php
@@ -0,0 +1,196 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Tests;
+
+use PHPUnit\Framework\TestCase;
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Data\BinaryObject;
+use Apache\Ignite\Data\Date;
+
+final class BinaryObjectTestCase extends TestCase
+{
+    const CACHE_NAME = '__php_test_cache';
+
+    const TYPE_NAME = 'TestClass';
+    const INNER_TYPE_NAME = 'InnerTestClass';
+    const STRING_VALUE = 'abc';
+    const DOUBLE_VALUE = 123.45;
+    const BOOL_VALUE = false;
+    const INT_VALUE = 456;
+    
+    private static $cache;
+
+    public static function setUpBeforeClass(): void
+    {
+        TestingHelper::init();
+        self::cleanUp();
+        self::$cache = TestingHelper::$client->getOrCreateCache(self::CACHE_NAME);
+    }
+
+    public static function tearDownAfterClass(): void
+    {
+        self::cleanUp();
+        TestingHelper::cleanUp();
+    }
+    
+    public function testBinaryObjectSetGetFields(): void
+    {
+        $cache = self::$cache;
+        try {
+            $obj1 = new BinaryObject(self::TYPE_NAME);
+            $obj1->setField('field_double', self::DOUBLE_VALUE);
+            $obj1->setField('field_string', self::STRING_VALUE);
+
+            $cache->put(2, $obj1);
+            $cache->put(3, $obj1);
+            $obj2 = $cache->get(2);
+            $this->assertTrue(TestingHelper::compare($obj1, $obj2));
+
+            $obj2->setField('field_double', $obj1->getField('field_double'));
+            $obj2->setField('field_string', $obj1->getField('field_string'));
+            $this->assertTrue(TestingHelper::compare($obj1, $obj2));
+
+            $obj3 = $cache->get(3);
+            $obj1->setField('field_double', $obj3->getField('field_double'));
+            $obj1->setField('field_string', $obj3->getField('field_string'));
+            $this->assertTrue(TestingHelper::compare($obj1, $obj3));
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    public function testBinaryObjectGetNonexistentField(): void
+    {
+        $cache = self::$cache;
+        try {
+            $obj1 = new BinaryObject(self::TYPE_NAME);
+            $obj1->setField('field_double', self::DOUBLE_VALUE);
+            $obj1->setField('field_string', self::STRING_VALUE);
+
+            $this->expectException(ClientException::class);
+            $obj1->getField('field_bool');
+
+            $cache->put(2, $obj1);
+            $obj2 = $cache->get(2);
+            $obj2->getField('field_bool');
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    public function testBinaryObjectRemoveField(): void
+    {
+        $cache = self::$cache;
+        try {
+            $obj1 = new BinaryObject(self::TYPE_NAME);
+            $obj1->setField('field_double', self::DOUBLE_VALUE);
+            $obj1->setField('field_string', self::STRING_VALUE);
+            $obj1->setField('field_bool', self::BOOL_VALUE);
+            $this->assertTrue($obj1->hasField('field_bool'));
+            $this->assertEquals($obj1->getField('field_bool'), self::BOOL_VALUE);
+
+            $obj1->removeField('field_bool');
+            $this->assertFalse($obj1->hasField('field_bool'));
+
+            $cache->put(3, $obj1);
+            $obj2 = $cache->get(3);
+            $this->assertTrue(TestingHelper::compare($obj1, $obj2));
+
+            $obj2->setField('field_bool', self::BOOL_VALUE);
+            $this->assertTrue($obj2->hasField('field_bool'));
+            $this->assertEquals($obj2->getField('field_bool'), self::BOOL_VALUE);
+
+            $obj2->removeField('field_bool');
+            $this->assertFalse($obj2->hasField('field_bool'));
+
+            $obj2->setField('field_bool', self::BOOL_VALUE);
+            $cache->put(4, $obj2);
+
+            $obj1->setField('field_bool', self::BOOL_VALUE);
+            $cache->put(5, $obj1);
+
+            $this->assertTrue(TestingHelper::compare($cache->get(4), $cache->get(5)));
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    public function testBinaryObjectOfDifferentSchemas(): void
+    {
+        $cache = self::$cache;
+        try {
+            $obj1 = new BinaryObject(self::TYPE_NAME);
+            $obj1->setField('field_int', self::INT_VALUE);
+            $obj1->setField('field_string', self::STRING_VALUE);
+            $obj1->setField('field_bool', self::BOOL_VALUE);
+            $cache->put(1, $obj1);
+
+            $obj2 = new BinaryObject(self::TYPE_NAME);
+            $obj2->setField('field_int', self::INT_VALUE);
+            $obj2->setField('field_bool', self::BOOL_VALUE);
+            $obj2->setField('field_date', new Date(12345));
+            $cache->put(2, $obj2);
+
+            $obj3 = $cache->get(1);
+            $obj3->removeField('field_string');
+            $obj4 = $cache->get(2);
+            $obj4->removeField('field_date');
+            $this->assertTrue(TestingHelper::compare($obj3, $obj4));
+
+            $cache->put(3, $obj3);
+            $cache->put(4, $obj4);
+            $this->assertTrue(TestingHelper::compare($cache->get(3), $cache->get(4)));
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    public function testNestedBinaryObjects(): void
+    {
+        $cache = self::$cache;
+        try {
+            $obj2 = new BinaryObject(self::INNER_TYPE_NAME);
+            $obj2->setField('field_int', self::INT_VALUE);
+            $obj2->setField('field_date', new Date(1234567));
+
+            $obj1 = new BinaryObject(self::TYPE_NAME);
+            $obj1->setField('field_double', self::DOUBLE_VALUE);
+            $obj1->setField('field_string', self::STRING_VALUE);
+            $obj1->setField('field_object', $obj2);
+
+            $cache->put(1, $obj1);
+            $obj3 = $cache->get(1);
+            $obj4 = $obj3->getField('field_object');
+            $obj4->setField('field_int', $obj4->getField('field_int') + 1);
+            $obj3->setField('field_object', $obj4);
+            $cache->put(3, $obj3);
+
+            $obj2->setField('field_int', self::INT_VALUE + 1);
+            $obj1->setField('field_object', $obj2);
+            $this->assertTrue(TestingHelper::compare($cache->get(3), $obj1));
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    private static function cleanUp(): void
+    {
+        TestingHelper::destroyCache(self::CACHE_NAME);
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/f28e4f3f/modules/platforms/php/tests/CacheKeyValueOpsTest.php
----------------------------------------------------------------------
diff --git a/modules/platforms/php/tests/CacheKeyValueOpsTest.php b/modules/platforms/php/tests/CacheKeyValueOpsTest.php
new file mode 100644
index 0000000..b7e1dea
--- /dev/null
+++ b/modules/platforms/php/tests/CacheKeyValueOpsTest.php
@@ -0,0 +1,763 @@
+<?php
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+namespace Apache\Ignite\Tests;
+
+use PHPUnit\Framework\TestCase;
+use Apache\Ignite\Exception\ClientException;
+use Apache\Ignite\Cache\CacheEntry;
+use Apache\Ignite\Cache\CacheConfiguration;
+use Apache\Ignite\Cache\CacheInterface;
+
+final class CacheKeyValueOpsTestCase extends TestCase
+{
+    const CACHE_NAME = '__php_test_cache';
+
+    public static function setUpBeforeClass(): void
+    {
+        TestingHelper::init();
+        self::cleanUp();
+        TestingHelper::$client->getOrCreateCache(self::CACHE_NAME);
+    }
+
+    public static function tearDownAfterClass(): void
+    {
+        self::cleanUp();
+        TestingHelper::cleanUp();
+    }
+    
+    public function testCacheGet(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $value = $cache->get(1);
+            $this->assertEquals($value, null);
+            $cache->put(1, 2);
+            $value = $cache->get(1);
+            $this->assertEquals($value, 2);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+    
+    public function cacheWrongKeys(): array
+    {
+        return array(
+            array(null)
+        );
+    }
+
+    /**
+     * @dataProvider cacheWrongKeys
+     */
+    public function testCacheGetWrongArgs($cacheKey): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $this->expectException(ClientException::class);
+            $cache->get($cacheKey);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+    
+    public function testCacheGetAll(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            for ($i = 0; $i < 5; $i++) {
+                $cache->put($i, $i * 2);
+            }
+            $entries = $cache->getAll([3, 4, 5, 6, 7]);
+            $this->assertCount(2, $entries);
+            foreach ($entries as $entry) {
+                $this->assertTrue($entry->getKey() === 3 || $entry->getKey() === 4);
+                $this->assertEquals($entry->getValue(), $entry->getKey() * 2);
+            }
+            $entries = $cache->getAll([6, 7, 8]);
+            $this->assertCount(0, $entries);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+    
+    public function cacheGetAllWrongKeys(): array
+    {
+        return array(
+            array([])
+        );
+    }
+
+    /**
+     * @dataProvider cacheGetAllWrongKeys
+     */
+    public function testCacheGetAllWrongArgs($keys): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $this->expectException(ClientException::class);
+            $cache->getAll($keys);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    public function testCachePut(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $value = $cache->get(1);
+            $this->assertEquals($value, null);
+            $cache->put(1, 2);
+            $value = $cache->get(1);
+            $this->assertEquals($value, 2);
+            $cache->put(1, 4);
+            $value = $cache->get(1);
+            $this->assertEquals($value, 4);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    public function cacheWrongKeyValues(): array
+    {
+        return array(
+            array(null, 1),
+            array(1, null),
+            array(null, null)
+        );
+    }
+
+    /**
+     * @dataProvider cacheWrongKeyValues
+     */
+    public function testCachePutWrongArgs($key, $value): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $this->expectException(ClientException::class);
+            $cache->put($key, $value);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    public function testCachePutAll(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $cacheEntries = array();
+            for ($i = 0; $i < 5; $i++) {
+                array_push($cacheEntries, new CacheEntry($i, $i * 2));
+            }
+            $cache->putAll($cacheEntries);
+            $entries = $cache->getAll([3, 4, 5, 6, 7]);
+            $this->assertCount(2, $entries);
+            foreach ($entries as $entry) {
+                $this->assertTrue($entry->getKey() === 3 || $entry->getKey() === 4);
+                $this->assertEquals($entry->getValue(), $entry->getKey() * 2);
+            }
+            $entries = $cache->getAll([-2, -1, 0, 1, 2, 3, 4, 5, 6, 7]);
+            $this->assertCount(5, $entries);
+            foreach ($entries as $entry) {
+                $this->assertTrue($entry->getKey() >= 0 && $entry->getKey() <= 4);
+                $this->assertEquals($entry->getValue(), $entry->getKey() * 2);
+            }
+            $entries = $cache->getAll([6, 7, 8]);
+            $this->assertCount(0, $entries);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+    
+    public function cachePutAllWrongArgs(): array
+    {
+        return array(
+            array([]),
+            array([new CacheConfiguration])
+        );
+    }
+
+    /**
+     * @dataProvider cachePutAllWrongArgs
+     */
+    public function testCachePutAllWrongArgs($entries): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $this->expectException(ClientException::class);
+            $cache->putAll($entries);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+    
+    public function testContainsKey(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $result = $cache->containsKey(1);
+            $this->assertFalse($result);
+            $cache->put(1, 2);
+            $result = $cache->containsKey(1);
+            $this->assertTrue($result);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+    
+    /**
+     * @dataProvider cacheWrongKeys
+     */
+    public function testContainsKeyWrongArgs($cacheKey): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $this->expectException(ClientException::class);
+            $cache->containsKey($cacheKey);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+  
+    public function testCacheContainsKeys(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $result = $cache->containsKeys([1, 2, 3]);
+            $this->assertFalse($result);
+            $cache->putAll([new CacheEntry(1, 2), new CacheEntry(2, 4)]);
+            $result = $cache->containsKeys([1, 2, 3]);
+            $this->assertFalse($result);
+            $cache->put(3, 6);
+            $result = $cache->containsKeys([1, 2, 3]);
+            $this->assertTrue($result);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+    
+    /**
+     * @dataProvider cacheGetAllWrongKeys
+     */
+    public function testCacheContainsKeysWrongArgs($keys): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $this->expectException(ClientException::class);
+            $cache->containsKeys($keys);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+    
+    public function testCacheGetAndPut(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $value = $cache->getAndPut(1, 2);
+            $this->assertEquals($value, null);
+            $value = $cache->getAndPut(1, 4);
+            $this->assertEquals($value, 2);
+            $cache->put(1, 6);
+            $value = $cache->getAndPut(1, 8);
+            $this->assertEquals($value, 6);
+            $value = $cache->get(1);
+            $this->assertEquals($value, 8);
+
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    /**
+     * @dataProvider cacheWrongKeyValues
+     */
+    public function testCacheGetAndPutWrongArgs($key, $value): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $this->expectException(ClientException::class);
+            $cache->getAndPut($key, $value);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    public function testCacheGetAndReplace(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $value = $cache->getAndReplace(1, 2);
+            $this->assertEquals($value, null);
+            $cache->put(1, 4);
+            $value = $cache->getAndReplace(1, 6);
+            $this->assertEquals($value, 4);
+            $value = $cache->get(1);
+            $this->assertEquals($value, 6);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    /**
+     * @dataProvider cacheWrongKeyValues
+     */
+    public function testCacheGetAndReplaceWrongArgs($key, $value): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $this->expectException(ClientException::class);
+            $cache->getAndReplace($key, $value);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+    
+    public function testCacheGetAndRemove(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $value = $cache->getAndRemove(1);
+            $this->assertEquals($value, null);
+            $cache->put(1, 2);
+            $value = $cache->getAndRemove(1);
+            $this->assertEquals($value, 2);
+            $value = $cache->get(1);
+            $this->assertEquals($value, null);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+    
+    /**
+     * @dataProvider cacheWrongKeys
+     */
+    public function testCacheGetAndRemoveWrongArgs($cacheKey): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $this->expectException(ClientException::class);
+            $cache->getAndRemove($cacheKey);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    public function testCachePutIfAbsent(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $result = $cache->putIfAbsent(1, 2);
+            $this->assertTrue($result);
+            $value = $cache->get(1);
+            $this->assertEquals($value, 2);
+            $result = $cache->putIfAbsent(1, 4);
+            $this->assertFalse($result);
+            $value = $cache->get(1);
+            $this->assertEquals($value, 2);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    /**
+     * @dataProvider cacheWrongKeyValues
+     */
+    public function testCachePutIfAbsentWrongArgs($key, $value): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $this->expectException(ClientException::class);
+            $cache->putIfAbsent($key, $value);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+  
+    public function testCacheGetAndPutIfAbsent(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $value = $cache->getAndPutIfAbsent(1, 2);
+            $this->assertEquals($value, null);
+            $value = $cache->get(1);
+            $this->assertEquals($value, 2);
+            $value = $cache->getAndPutIfAbsent(1, 4);
+            $this->assertEquals($value, 2);
+            $value = $cache->get(1);
+            $this->assertEquals($value, 2);
+
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    /**
+     * @dataProvider cacheWrongKeyValues
+     */
+    public function testCacheGetAndPutIfAbsentWrongArgs($key, $value): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $this->expectException(ClientException::class);
+            $cache->getAndPutIfAbsent($key, $value);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    public function testCacheReplace(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $result = $cache->replace(1, 2);
+            $this->assertFalse($result);
+            $value = $cache->get(1);
+            $this->assertEquals($value, null);
+            $cache->put(1, 1);
+            $result = $cache->replace(1, 4);
+            $this->assertTrue($result);
+            $value = $cache->get(1);
+            $this->assertEquals($value, 4);
+
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    /**
+     * @dataProvider cacheWrongKeyValues
+     */
+    public function testCacheReplaceWrongArgs($key, $value): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $this->expectException(ClientException::class);
+            $cache->replace($key, $value);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+    
+    public function testCacheReplaceIfEquals(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $result = $cache->replaceIfEquals(1, 2, 3);
+            $this->assertFalse($result);
+            $cache->put(1, 4);
+            $result = $cache->replaceIfEquals(1, 2, 3);
+            $this->assertFalse($result);
+            $value = $cache->get(1);
+            $this->assertEquals($value, 4);
+            $result = $cache->replaceIfEquals(1, 4, 3);
+            $this->assertTrue($result);
+            $value = $cache->get(1);
+            $this->assertEquals($value, 3);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    public function cacheWrongReplaceIfEqualsArgs(): array
+    {
+        return array(
+            array(null, 1, 1),
+            array(null, 1, null),
+            array(1, null, 1),
+            array(1, null, null),
+            array(null, null, null)
+        );
+    }
+
+    /**
+     * @dataProvider cacheWrongReplaceIfEqualsArgs
+     */
+    public function testCacheReplaceIfEqualsWrongArgs($key, $value, $newValue): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $this->expectException(ClientException::class);
+            $cache->replaceIfEquals($key, $value, $newValue);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+  
+    public function testCacheClear(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $cache->clear();
+            $result = $cache->getSize();
+            $this->assertEquals($result, 0);
+            $cache->putAll([new CacheEntry(1, 2), new CacheEntry(2, 4), new CacheEntry(3, 6)]);
+            $result = $cache->getSize();
+            $this->assertEquals($result, 3);
+            $cache->clear();
+            $result = $cache->getSize();
+            $this->assertEquals($result, 0);
+            $entries = $cache->getAll([1, 2, 3]);
+            $this->assertCount(0, $entries);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    public function testCacheClearKeys(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $cache->clearKeys([1, 2, 3]);
+            $result = $cache->getSize();
+            $this->assertEquals($result, 0);
+            $cache->putAll([new CacheEntry(1, 2), new CacheEntry(2, 4), new CacheEntry(3, 6)]);
+            $result = $cache->getSize();
+            $this->assertEquals($result, 3);
+            $cache->clearKeys([1, 2, 7, 8]);
+            $result = $cache->getSize();
+            $this->assertEquals($result, 1);
+            $value = $cache->get(3);
+            $this->assertEquals($value, 6);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+    
+    /**
+     * @dataProvider cacheGetAllWrongKeys
+     */
+    public function testCacheClearKeysWrongArgs($keys): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $this->expectException(ClientException::class);
+            $cache->clearKeys($keys);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    public function testCacheClearKey(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $cache->clearKey(1);
+            $result = $cache->getSize();
+            $this->assertEquals($result, 0);
+            $cache->putAll([new CacheEntry(1, 2), new CacheEntry(2, 4), new CacheEntry(3, 6)]);
+            $result = $cache->getSize();
+            $this->assertEquals($result, 3);
+            $cache->clearKey(1);
+            $result = $cache->getSize();
+            $this->assertEquals($result, 2);
+            $value = $cache->get(2);
+            $this->assertEquals($value, 4);
+            $value = $cache->get(3);
+            $this->assertEquals($value, 6);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+    
+    /**
+     * @dataProvider cacheWrongKeys
+     */
+    public function testCacheClearKeyWrongArgs($cacheKey): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $this->expectException(ClientException::class);
+            $cache->clearKey($cacheKey);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    public function testCacheRemoveKey(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $result = $cache->removeKey(1);
+            $this->assertFalse($result);
+            $result = $cache->getSize();
+            $this->assertEquals($result, 0);
+            $cache->putAll([new CacheEntry(1, 2), new CacheEntry(2, 4), new CacheEntry(3, 6)]);
+            $result = $cache->getSize();
+            $this->assertEquals($result, 3);
+            $result = $cache->removeKey(1);
+            $this->assertTrue($result);
+            $result = $cache->removeKey(1);
+            $this->assertFalse($result);
+            $result = $cache->getSize();
+            $this->assertEquals($result, 2);
+            $value = $cache->get(2);
+            $this->assertEquals($value, 4);
+            $value = $cache->get(3);
+            $this->assertEquals($value, 6);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+    
+    /**
+     * @dataProvider cacheWrongKeys
+     */
+    public function testCacheRemoveKeyWrongArgs($cacheKey): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $this->expectException(ClientException::class);
+            $cache->removeKey($cacheKey);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+    
+    public function testRemoveIfEquals(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $result = $cache->removeIfEquals(1, 2);
+            $this->assertFalse($result);
+            $cache->put(1, 4);
+            $result = $cache->removeIfEquals(1, 2);
+            $this->assertFalse($result);
+            $result = $cache->removeIfEquals(1, 4);
+            $this->assertTrue($result);
+            $value = $cache->get(1);
+            $this->assertEquals($value, null);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    /**
+     * @dataProvider cacheWrongKeyValues
+     */
+    public function testRemoveIfEqualsWrongArgs($key, $value): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $this->expectException(ClientException::class);
+            $cache->removeIfEquals($key, $value);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+    
+    public function testCacheRemoveKeys(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $cache->removeKeys([1, 2, 3]);
+            $result = $cache->getSize();
+            $this->assertEquals($result, 0);
+            $cache->putAll([new CacheEntry(1, 2), new CacheEntry(2, 4), new CacheEntry(3, 6)]);
+            $result = $cache->getSize();
+            $this->assertEquals($result, 3);
+            $cache->removeKeys([1, 2, 7, 8]);
+            $result = $cache->getSize();
+            $this->assertEquals($result, 1);
+            $value = $cache->get(3);
+            $this->assertEquals($value, 6);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+    
+    /**
+     * @dataProvider cacheGetAllWrongKeys
+     */
+    public function testCacheRemoveKeysWrongArgs($keys): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $this->expectException(ClientException::class);
+            $cache->removeKeys($keys);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+
+    public function testCacheRemoveAll(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $cache->removeAll();
+            $result = $cache->getSize();
+            $this->assertEquals($result, 0);
+            $cache->putAll([new CacheEntry(1, 2), new CacheEntry(2, 4), new CacheEntry(3, 6)]);
+            $result = $cache->getSize();
+            $this->assertEquals($result, 3);
+            $cache->removeAll();
+            $result = $cache->getSize();
+            $this->assertEquals($result, 0);
+            $entries = $cache->getAll([1, 2, 3]);
+            $this->assertCount(0, $entries);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+    
+    public function testCacheGetSize(): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $result = $cache->getSize();
+            $this->assertEquals($result, 0);
+            $cache->putAll([new CacheEntry(1, 2), new CacheEntry(2, 4), new CacheEntry(3, 6)]);
+            $result = $cache->getSize();
+            $this->assertEquals($result, 3);
+            $result = $cache->getSize(CacheInterface::PEEK_MODE_ALL);
+            $this->assertEquals($result, 3);
+            $result = $cache->getSize(CacheInterface::PEEK_MODE_ALL, CacheInterface::PEEK_MODE_ALL);
+            $this->assertEquals($result, 3);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+    
+    public function getSizeWrongArgs(): array
+    {
+        return array(
+            array(-1, -2),
+            array(4, 5, 6, 0)
+        );
+    }
+
+    /**
+     * @dataProvider getSizeWrongArgs
+     */
+    public function testCacheGetSizeWrongArgs($modes): void
+    {
+        $cache = TestingHelper::$client->getCache(self::CACHE_NAME);
+        try {
+            $this->expectException(ClientException::class);
+            $cache->getSize($modes);
+        } finally {
+            $cache->removeAll();
+        }
+    }
+    
+    private static function cleanUp(): void
+    {
+        TestingHelper::destroyCache(self::CACHE_NAME);
+    }
+}