├── .meta-storm.xml ├── .phpunit-watcher.yml ├── .styleci.yml ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json ├── infection.json.dist ├── psalm.xml ├── rector.php └── src └── Json.php /.meta-storm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.phpunit-watcher.yml: -------------------------------------------------------------------------------- 1 | watch: 2 | directories: 3 | - src 4 | - tests 5 | fileMask: '*.php' 6 | notifications: 7 | passingTests: false 8 | failingTests: false 9 | phpunit: 10 | binaryPath: vendor/bin/phpunit 11 | timeout: 180 12 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: psr12 2 | risky: true 3 | 4 | version: 8.1 5 | 6 | finder: 7 | exclude: 8 | - docs 9 | - vendor 10 | 11 | enabled: 12 | - alpha_ordered_traits 13 | - array_indentation 14 | - array_push 15 | - combine_consecutive_issets 16 | - combine_consecutive_unsets 17 | - combine_nested_dirname 18 | - declare_strict_types 19 | - dir_constant 20 | - fully_qualified_strict_types 21 | - function_to_constant 22 | - hash_to_slash_comment 23 | - is_null 24 | - logical_operators 25 | - magic_constant_casing 26 | - magic_method_casing 27 | - method_separation 28 | - modernize_types_casting 29 | - native_function_casing 30 | - native_function_type_declaration_casing 31 | - no_alias_functions 32 | - no_empty_comment 33 | - no_empty_phpdoc 34 | - no_empty_statement 35 | - no_extra_block_blank_lines 36 | - no_short_bool_cast 37 | - no_superfluous_elseif 38 | - no_unneeded_control_parentheses 39 | - no_unneeded_curly_braces 40 | - no_unneeded_final_method 41 | - no_unset_cast 42 | - no_unused_imports 43 | - no_unused_lambda_imports 44 | - no_useless_else 45 | - no_useless_return 46 | - normalize_index_brace 47 | - php_unit_dedicate_assert 48 | - php_unit_dedicate_assert_internal_type 49 | - php_unit_expectation 50 | - php_unit_mock 51 | - php_unit_mock_short_will_return 52 | - php_unit_namespaced 53 | - php_unit_no_expectation_annotation 54 | - phpdoc_no_empty_return 55 | - phpdoc_no_useless_inheritdoc 56 | - phpdoc_order 57 | - phpdoc_property 58 | - phpdoc_scalar 59 | - phpdoc_singular_inheritdoc 60 | - phpdoc_trim 61 | - phpdoc_trim_consecutive_blank_line_separation 62 | - phpdoc_type_to_var 63 | - phpdoc_types 64 | - phpdoc_types_order 65 | - print_to_echo 66 | - regular_callable_call 67 | - return_assignment 68 | - self_accessor 69 | - self_static_accessor 70 | - set_type_to_cast 71 | - short_array_syntax 72 | - short_list_syntax 73 | - simplified_if_return 74 | - single_quote 75 | - standardize_not_equals 76 | - ternary_to_null_coalescing 77 | - trailing_comma_in_multiline_array 78 | - unalign_double_arrow 79 | - unalign_equals 80 | - empty_loop_body_braces 81 | - integer_literal_case 82 | - union_type_without_spaces 83 | 84 | disabled: 85 | - function_declaration 86 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Yii JSON Change Log 2 | 3 | ## 1.0.1 under development 4 | 5 | - Bug #41: Fix bug with instances of extended `DateTime` class (@Tigrov) 6 | - Enh #41: Improve performance of `Json::encode()` method by 10-20% (@Tigrov) 7 | - Chg #56: Change PHP constraint in `composer.json` to `~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0` (@vjik) 8 | 9 | ## 1.0.0 August 26, 2020 10 | 11 | - Initial release. 12 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright © 2008 by Yii Software () 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions 6 | are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the 13 | distribution. 14 | * Neither the name of Yii Software nor the names of its 15 | contributors may be used to endorse or promote products derived 16 | from this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 28 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | Yii 4 | 5 |

Yii JSON

6 |
7 |

8 | 9 | [![Latest Stable Version](https://poser.pugx.org/yiisoft/json/v)](https://packagist.org/packages/yiisoft/json) 10 | [![Total Downloads](https://poser.pugx.org/yiisoft/json/downloads)](https://packagist.org/packages/yiisoft/json) 11 | [![Build status](https://github.com/yiisoft/json/actions/workflows/build.yml/badge.svg)](https://github.com/yiisoft/json/actions/workflows/build.yml) 12 | [![Code Coverage](https://codecov.io/gh/yiisoft/json/branch/master/graph/badge.svg)](https://codecov.io/gh/yiisoft/json) 13 | [![Mutation testing badge](https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fyiisoft%2Fjson%2Fmaster)](https://dashboard.stryker-mutator.io/reports/github.com/yiisoft/json/master) 14 | [![Static analysis](https://github.com/yiisoft/json/actions/workflows/static.yml/badge.svg?branch=master)](https://github.com/yiisoft/json/actions/workflows/static.yml?query=branch%3Amaster) 15 | [![type-coverage](https://shepherd.dev/github/yiisoft/json/coverage.svg)](https://shepherd.dev/github/yiisoft/json) 16 | 17 | The package provides methods to encode and decode JSON. 18 | 19 | - It always throws `\JsonException` instead of returning false on error. 20 | - It has sensible defaults, so you don't have to specify flags all the time. 21 | - It has handy method to encode for HTML safely. 22 | - It handles `\JsonSerializable`, `\DateTimeInterface`, and `\SimpleXMLElement` well. 23 | 24 | ## Requirements 25 | 26 | - PHP 7.4 or higher. 27 | - `JSON` PHP extension. 28 | - `SimpleXML` PHP extension. 29 | 30 | ## Installation 31 | 32 | The package could be installed with [Composer](https://getcomposer.org): 33 | 34 | ```shell 35 | composer require yiisoft/json 36 | ``` 37 | 38 | ## General usage 39 | 40 | Encoding: 41 | 42 | ```php 43 | use \Yiisoft\Json\Json; 44 | 45 | $data = ['name' => 'Alex', 'team' => 'Yii']; 46 | $json = Json::encode($data); 47 | ``` 48 | 49 | Encoding for HTML: 50 | 51 | ```php 52 | use \Yiisoft\Json\Json; 53 | 54 | $data = ['name' => 'Alex', 'team' => 'Yii']; 55 | $json = Json::htmlEncode($data); 56 | ``` 57 | 58 | Decoding: 59 | 60 | ```php 61 | use \Yiisoft\Json\Json; 62 | 63 | $json = '{"name":"Alex","team":"Yii"}'; 64 | $data = Json::decode($json); 65 | ``` 66 | 67 | ## Documentation 68 | 69 | - [Internals](docs/internals.md) 70 | 71 | If you need help or have a question, the [Yii Forum](https://forum.yiiframework.com/c/yii-3-0/63) is a good place for that. 72 | You may also check out other [Yii Community Resources](https://www.yiiframework.com/community). 73 | 74 | ## License 75 | 76 | The Yii JSON is free software. It is released under the terms of the BSD License. 77 | Please see [`LICENSE`](./LICENSE.md) for more information. 78 | 79 | Maintained by [Yii Software](https://www.yiiframework.com/). 80 | 81 | ## Support the project 82 | 83 | [![Open Collective](https://img.shields.io/badge/Open%20Collective-sponsor-7eadf1?logo=open%20collective&logoColor=7eadf1&labelColor=555555)](https://opencollective.com/yiisoft) 84 | 85 | ## Follow updates 86 | 87 | [![Official website](https://img.shields.io/badge/Powered_by-Yii_Framework-green.svg?style=flat)](https://www.yiiframework.com/) 88 | [![Twitter](https://img.shields.io/badge/twitter-follow-1DA1F2?logo=twitter&logoColor=1DA1F2&labelColor=555555?style=flat)](https://twitter.com/yiiframework) 89 | [![Telegram](https://img.shields.io/badge/telegram-join-1DA1F2?style=flat&logo=telegram)](https://t.me/yii3en) 90 | [![Facebook](https://img.shields.io/badge/facebook-join-1DA1F2?style=flat&logo=facebook&logoColor=ffffff)](https://www.facebook.com/groups/yiitalk) 91 | [![Slack](https://img.shields.io/badge/slack-join-1DA1F2?style=flat&logo=slack)](https://yiiframework.com/go/slack) 92 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yiisoft/json", 3 | "type": "library", 4 | "description": "Yii JSON encoding and decoding", 5 | "keywords": [ 6 | "json" 7 | ], 8 | "homepage": "https://www.yiiframework.com/", 9 | "license": "BSD-3-Clause", 10 | "support": { 11 | "issues": "https://github.com/yiisoft/json/issues?state=open", 12 | "source": "https://github.com/yiisoft/json", 13 | "forum": "https://www.yiiframework.com/forum/", 14 | "wiki": "https://www.yiiframework.com/wiki/", 15 | "irc": "ircs://irc.libera.chat:6697/yii", 16 | "chat": "https://t.me/yii3en" 17 | }, 18 | "funding": [ 19 | { 20 | "type": "opencollective", 21 | "url": "https://opencollective.com/yiisoft" 22 | }, 23 | { 24 | "type": "github", 25 | "url": "https://github.com/sponsors/yiisoft" 26 | } 27 | ], 28 | "require": { 29 | "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", 30 | "ext-json": "*", 31 | "ext-simplexml": "*" 32 | }, 33 | "require-dev": { 34 | "maglnet/composer-require-checker": "^3.8 || ^4.2", 35 | "phpunit/phpunit": "^9.6.22", 36 | "rector/rector": "^2.0.8", 37 | "roave/infection-static-analysis-plugin": "^1.18", 38 | "spatie/phpunit-watcher": "^1.23.6", 39 | "vimeo/psalm": "^4.30 || ^5.26.1 || ^6.5" 40 | }, 41 | "autoload": { 42 | "psr-4": { 43 | "Yiisoft\\Json\\": "src" 44 | } 45 | }, 46 | "autoload-dev": { 47 | "psr-4": { 48 | "Yiisoft\\Json\\Tests\\": "tests" 49 | } 50 | }, 51 | "config": { 52 | "sort-packages": true, 53 | "bump-after-update": "dev", 54 | "allow-plugins": { 55 | "infection/extension-installer": true, 56 | "composer/package-versions-deprecated": true 57 | } 58 | }, 59 | "prefer-stable": true, 60 | "scripts": { 61 | "test": "phpunit --testdox --no-interaction", 62 | "test-watch": "phpunit-watcher watch" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /infection.json.dist: -------------------------------------------------------------------------------- 1 | { 2 | "source": { 3 | "directories": [ 4 | "src" 5 | ] 6 | }, 7 | "logs": { 8 | "text": "php:\/\/stderr", 9 | "stryker": { 10 | "report": "master" 11 | } 12 | }, 13 | "mutators": { 14 | "@default": true 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /psalm.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /rector.php: -------------------------------------------------------------------------------- 1 | paths([ 12 | __DIR__ . '/src', 13 | __DIR__ . '/tests', 14 | ]); 15 | 16 | // register a single rule 17 | $rectorConfig->rule(InlineConstructorDefaultToPropertyRector::class); 18 | 19 | // define sets of rules 20 | $rectorConfig->sets([ 21 | LevelSetList::UP_TO_PHP_74, 22 | ]); 23 | 24 | $rectorConfig->skip([ 25 | ClosureToArrowFunctionRector::class, 26 | ]); 27 | }; 28 | -------------------------------------------------------------------------------- /src/Json.php: -------------------------------------------------------------------------------- 1 | $depth 41 | * 42 | * @throws JsonException if there is any encoding error. 43 | * 44 | * @return string The encoding result. 45 | */ 46 | public static function encode( 47 | $value, 48 | int $options = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR, 49 | int $depth = 512 50 | ): string { 51 | if (is_array($value)) { 52 | $value = self::processArray($value); 53 | } elseif (is_object($value)) { 54 | $value = self::processObject($value); 55 | } 56 | 57 | /** 58 | * @var string We use flag `JSON_THROW_ON_ERROR`, so `json_encode` never returns `false`. 59 | */ 60 | return json_encode($value, JSON_THROW_ON_ERROR | $options, $depth); 61 | } 62 | 63 | /** 64 | * Encodes the given value into a JSON string HTML-escaping entities so it is safe to be embedded in HTML code. 65 | * 66 | * Note that data encoded as JSON must be UTF-8 encoded according to the JSON specification. 67 | * You must ensure strings passed to this method have proper encoding before passing them. 68 | * 69 | * @param mixed $value The data to be encoded. 70 | * 71 | * @throws JsonException If there is any encoding error. 72 | * 73 | * @return string The encoding result. 74 | */ 75 | public static function htmlEncode($value): string 76 | { 77 | return self::encode( 78 | $value, 79 | JSON_UNESCAPED_UNICODE | JSON_HEX_QUOT | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_THROW_ON_ERROR 80 | ); 81 | } 82 | 83 | /** 84 | * Decodes the given JSON string into a PHP data structure. 85 | * 86 | * @param string $json The JSON string to be decoded. 87 | * @param bool $asArray Whether to return objects in terms of associative arrays. 88 | * @param int $depth The recursion depth. 89 | * @param int $options The decode options. 90 | * 91 | * @psalm-param int<1, 2147483647> $depth 92 | * 93 | * @throws JsonException If there is any decoding error. 94 | * 95 | * @return mixed The PHP data. 96 | */ 97 | public static function decode( 98 | string $json, 99 | bool $asArray = true, 100 | int $depth = 512, 101 | int $options = JSON_THROW_ON_ERROR 102 | ) { 103 | if ($json === '') { 104 | return null; 105 | } 106 | return json_decode($json, $asArray, $depth, JSON_THROW_ON_ERROR | $options); 107 | } 108 | 109 | /** 110 | * Pre-processes the array before sending it to `json_encode()`. 111 | * 112 | * @param array $data The array to be processed. 113 | * 114 | * @return array The processed array. 115 | */ 116 | private static function processArray(array $data): array 117 | { 118 | foreach ($data as $key => $value) { 119 | if (is_array($value)) { 120 | $data[$key] = self::processArray($value); 121 | } elseif (is_object($value)) { 122 | $data[$key] = self::processObject($value); 123 | } 124 | } 125 | 126 | return $data; 127 | } 128 | 129 | /** 130 | * Pre-processes the object before sending it to `json_encode()`. 131 | * 132 | * @param object $data The object to be processed. 133 | * 134 | * @return mixed The processed data. 135 | */ 136 | private static function processObject(object $data) 137 | { 138 | if ($data instanceof JsonSerializable) { 139 | $data = $data->jsonSerialize(); 140 | 141 | if (is_array($data)) { 142 | return self::processArray($data); 143 | } 144 | 145 | if (is_object($data)) { 146 | return self::processObject($data); 147 | } 148 | 149 | return $data; 150 | } 151 | 152 | if ($data instanceof DateTimeInterface) { 153 | return $data; 154 | } 155 | 156 | if ($data instanceof SimpleXMLElement) { 157 | return (array)$data ?: new stdClass(); 158 | } 159 | 160 | if ($data instanceof Traversable) { 161 | return self::processArray(iterator_to_array($data)) ?: new stdClass(); 162 | } 163 | 164 | return self::processArray(get_object_vars($data)) ?: new stdClass(); 165 | } 166 | } 167 | --------------------------------------------------------------------------------