在最近项目中,前后端联调的时候php接口返回数组json后的数据,有时候是数组,有的时候却是对象,导致前端解析的时候总是抱怨数据问题。今天就对这个问题进行梳理。(已解决,json_encode时设置JSON_FORCE_OBJECT选项即可。)
json是一种轻量级的数据交换文本格式。
2.1 对象(object)
一个对象以{
开始,并以}
结束。一个对象包含一系列非排序的名称/值
对,每个名称/值
对之间使用,
分区。例如:
{name:value}
2.2 名称/值(collection)
名称和值之间使用:
隔开,一般的形式是{name:value}
。
2.3 值的有序列表(Array)
一个或者多个值用,
分区后,使用[
,]
括起来就形成了列表,例如:
[collection, collection]
2.4 字符串
以"
、"
括起来的一串字符.
2.5 数值
一系列0-9的数字组合,可以为负数或者小数。还可以用e或者E表示为指数形式。
2.6 布尔值
用true
或者false
表示。
Note: When encoding an array, if the keys are not a continuous numeric sequence starting from 0, all keys are encoded as strings, and specified explicitly for each key-value pair. – via php manual
也就是说php的数组做json_encode的时候,只有数组的下标是从0开始的连续整数,才会json为列表形式;其他情况都是对象形式。
因此,针对php数组json_encode时,需要数组形式的话就重新排序一下数组即可。
当对php的数组进行json_encode的时候,可以设置option为JSON_FORCE_OBJECT,即可强制设置编码为JSON的对象。
string json_encode ( mixed $value [, int $options = 0 [, int $depth = 512 ]] )
JSON_FORCE_OBJECT (integer) Outputs an object rather than an array when a non-associative array is used. Especially useful when the recipient of the output is expecting an object and the array is empty. Available since PHP 5.3.0.
$arr = array(
'a' => 'first',
'b' => 'second',
'c' => 'third',
'd' => 'fourth',
);
print_r(array_keys($arr));
// Array
// (
// [0] => a
// [1] => b
// [2] => c
// [3] => d
// )
$arr = array(
'a' => 'first',
'b' => 'second',
'c' => 'third',
'd' => 'fourth',
);
print_r(array_values($arr));
// Array
// (
// [0] => first
// [1] => second
// [2] => third
// [3] => fourth
// )
$arr = array(
'a' => 'first',
'b' => 'second',
'c' => 'third',
'd' => 'fourth',
);
$newarr = array(
'd' => '4th',
'e' => '5th',
);
print_r($arr + $newarr);
// Array
// (
// [a] => first
// [b] => second
// [c] => third
// [d] => fourth
// [e] => 5th
// )
注意:两个数组key相等时,第二个数组不会覆盖第一个数组的value
$arr = array(
'a' => 'first',
'b' => 'second',
'c' => 'third',
'd' => 'fourth',
);
$newarr = array(
'd' => '4th',
'e' => '5th',
);
print_r(array_merge($arr, $newarr));
// Array
// (
// [a] => first
// [b] => second
// [c] => third
// [d] => 4th
// [e] => 5th
// )
注意:两个数组key相等时,第二个数组会覆盖第一个数组的value
$arr = array(
'a' => 'first',
'b' => 'second',
// 'c' => 'third',
// 'd' => 'fourth',
);
$newarr = array(
'd' => '4th',
'e' => '5th',
);
print_r(array_combine($arr, $newarr));
// Array
// (
// [first] => 4th
// [second] => 5th
// )
注意:两个数组的元素个数要一致
$arr = array(
'a' => 'first',
'b' => 'second',
'c' => 'third',
'd' => 'fourth',
);
print_r(array_shift($arr));
// first
$a = array(
array(
'id' => 5698,
'first_name' => 'Bill',
'last_name' => 'Gates',
),
array(
'id' => 4767,
'first_name' => 'Steve',
'last_name' => 'Jobs',
),
array(
'id' => 3809,
'first_name' => 'Mark',
'last_name' => 'Zuckerberg',
)
);
print_r(array_column($a, 'last_name'));
// Array
// (
// [0] => Gates
// [1] => Jobs
// [2] => Zuckerberg
// )
注意:php版本要5.5+
$arr = array(
'a' => 'first',
'b' => 'second',
'c' => 'third',
'd' => 'fourth',
'e' => 'fourth',
);
print_r(array_unique($arr));
// Array
// (
// [a] => first
// [b] => second
// [c] => third
// [d] => fourth
// )
注意:当几个数组元素的值相等时,只保留第一个元素,其他的元素被删除。
$arr = array(
'a' => 'first',
'b' => 'second',
'c' => 'third',
'd' => 'fourth',
);
$newarr = array(
'd' => '4th',
'e' => '5th',
);
print_r(array_replace($arr, $newarr));
// Array
// (
// [a] => first
// [b] => second
// [c] => third
// [d] => 4th
// [e] => 5th
// )
注意:如果一个键存在于第一个数组 array1 同时也存在于第二个数组 array2,第一个数组 array1 中的值将被第二个数组 array2 中的值替换。如果一个键仅存在于第一个数组 array1,它将保持不变。如果一个键存在于第二个数组 array2,但是不存在于第一个数组 array1,则会在第一个数组 array1 中创建这个元素。php版本5.3.0+
$arr = array(
'a' => '1',
'b' => '2',
'c' => '3',
'd' => '4',
);
print_r(array_sum($arr));
// 10
$arr = array(
'a' => '3',
'b' => '2',
'c' => '2',
'd' => '4',
);
function my_sort($a,$b)
{
if ($a==$b) return 0;
return ($a<$b)?-1:1;
}
usort($arr,"my_sort");
print_r($arr);
// Array
// (
// [0] => 2
// [1] => 2
// [2] => 3
// [3] => 4
// )
$arr = array(
'a' => '3',
'b' => '2',
'c' => '2',
'd' => '4',
);
print_r(array_count_values($arr));
// Array
// (
// [3] => 1
// [2] => 2
// [4] => 1
// )
print_r(array_fill(3, 6, 'filled'));
// Array
// (
// [3] => filled
// [4] => filled
// [5] => filled
// [6] => filled
// [7] => filled
// [8] => filled
// )
$arr = array(
'a' => 'first',
'b' => 'second',
'c' => 'third',
'd' => 'fourth',
'e' => 'fourth',
);
print_r(array_flip(array_flip($arr)));
// 注意与array_unique的区别
// Array
// (
// [a] => first
// [b] => second
// [c] => third
// [e] => fourth
// )
print_r(array_unique($arr));
// Array
// (
// [a] => first
// [b] => second
// [c] => third
// [d] => fourth
// )
注意:函数返回一个反转后的数组,如果同一值出现了多次,则最后一个键名将作为它的值,所有其他的键名都将丢失。
在mac本机启动java web的时候,出现下面报错:
错误: 代理抛出异常错误: java.net.MalformedURLException: Local host name unknown: java.net.UnknownHostException: bogon: bogon: nodename nor servname provided, or not known
mac的终端会先向DNS查询当前ip对应的反向域名解析的结果,如果查询不到再显示我们设置的计算机名。由于DNS服务错误地将保留地址反向的NS查询结果返回为bogon(虚拟、虚伪),而不是localhost,导致计算机名变成了bogon,又导致程序出错。
设置hostname
sudo hostname your-desired-host-name
sudo scutil --set LocalHostName $(hostname)
sudo scutil --set HostName $(hostname)
设置DNS为8.8.8.8
。
Composer是PHP的依赖管理工具。我们只要声明项目中依赖的代码库,Composer能自动帮我们下载安装。
安装Composer,并且安装到全局目录中。
$ curl -sS https://getcomposer.org/installer | php
$ mv composer.phar /usr/local/bin/composer
这样就能直接使用composer命令。
$ composer
composer.json
文件在项目根目录中创建composer.json
文件
{
"require": {
"monolog/monolog": "1.0.*"
}
}
在项目根目录执行命令:
$ composer install
composer会自动帮我们下载依赖,结构如下:
这时我们的项目中还会出现composer.lock
文件,composer.lock
文件中记录着依赖的版本号等信息。我们需要将该文件也提交到我们代码库中,这样任何人建立项目都是用的完全相同的依赖。
composer会自动帮我们生成vendor/autoload.php
文件。我们只需引入这个文件,就能自动加载相应的库。
require 'vendor/autoload.php';
在项目中,我们就可以直接使用相应的库功能。
$log = new Monolog\Logger('name');
$log->pushHandler(new Monolog\Handler\StreeamHandler('app.log', Monolog\Logger::WARNING));
$log->addWarning('Foo');
composer是php的依赖管理工具,本文简单介绍其基本使用,更多内容请阅读官方文档。
在实际的生产环境中,各个系统都独立部署。系统间通过RPC调用,与单机环境有很多不同的地方。本文记录一些常见的case,希望对以后的开发中规避这些问题。
有些场景下,我们需要先更新数据库然后读出数据再进行其他操作,这种在单机环境中不会有任何问题。但是实际生产环境数据库的部署是分主从的,主库用来更新操作,从库主要承担读的压力。数据库请求到来的时候,数据库上层有一个proxy,根据sql语句分发请求分别到主、从库。但是数据从主库同步到从库是有一定的时间间隔的,这个间隔从毫秒级到秒级都有可能,因此业务逻辑中要规避这种情况。
解决方案:
* 业务中规避先写再读的case,尽量通过程序控制先读再写。
* 对于必须要求先写再读的业务逻辑,可以联系dba,让这部分的读分发到主库。
php业务中对外请求时,我们会设置超时时间,如果是秒级的超时,我们这样设置是没问题的:
$timeout = 2; //2s超时
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); //连接超时
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); //处理超时
但是实际业务中常常需要设置毫秒级的超时时间,例如$timeout = 0.1;//100ms超时
再用上面的语句就会有问题了,你会发现超时时间根本没起作用。原因见 Curl的毫秒超时的一个”Bug”。如果需要毫秒级超时,必须设置CURLOPT_NOSIGNAL参数。
$timeout = 0.1;//100ms超时
curl_setopt($ch, CURLOPT_NOSIGNAL, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, $timeout * 1000);
curl_setopt($ch, CURLOPT_TIMEOUT_MS, $timeout * 1000);
xdebug是一个开源的php代码调试工具,支持运行时栈输出,运行时函数调用跟踪,代码覆盖率分析,性能数据采集以及内部状态显示
在xdebug下载页,我们选择合适的版本进行安装,本文使用centos系列。
$ wget http://xdebug.org/files/xdebug-2.3.3.tgz
$ tar zxvf xdebug-2.3.3.tgz
$ cd xdebug-2.3.3
$ phpize
$ ./configure
$ make && make install
修改php.ini文件
[Xdebug]
xdebug.profiler_enable=On
xdebug.trace_output_dir=/YOU_WANT_TO_SAVE_PATH/xdebug-output
xdebug.profiler_output_dir=/YOU_WANT_TO_SAVE_PATH/xdebug-output
web服务需要重启php-fpm
现在每次调用php脚本,就会自动在YOU_WANT_TO_SAVE_PATH/xdebug-output
生成相应的新能数据文件。
性能文件可以使用专门的工具(win/mac下可以使用QCacheGrind,linux下可以使用KCacheGrind)。以QCacheGrind为例,界面左侧”Flat Profile”展示函数调用列表,Incl.
包括子函数的调用时间,Self
为去除子函数后自身消耗的时间。
示例代码
//test.php
<?php
testXdebug();
function testXdebug() {
require_once('abc.php');
}
//abc.php
<?php
echo "hello";
profile分析效果: