① php软件开发中如何提高项目的运行效率
PHP软件开发中如何提高项目的运行效率
如何提高PHP程序执行效率?编程习惯分析,PHP程序原本是解释性程序语言,其执行速度本来就不高,如果在日常开发中不注意编程习惯就很难提高其执行效率,下文从PHP编程和mysql数据效率两个方面分析哪些提高其执行效率的要点PHP软件开发中如何提高项目的运行效率
一、PHP提高效率的要点
1、如果能将类的方法定义成static,就尽量定义成static,它的速度会提升将近4倍。
2、$row[’id’] 的速度是$row[id]的7倍。
3、echo 比 print 快,并且使用echo的多重参数(译注:指用逗号而不是句点)代替字符串连接,比如echo $str1,$str2。
4、在执行for循环之前确定最大循环数,不要每循环一次都计算最大值,最好运用foreach代替。
5、注销那些不用的变量尤其是大数组,以便释放内存。
6、尽量避免使用__get,__set,__autoload。
7、require_once()代价昂贵。
8、include文件时尽量使用绝对路径,因为它避免了PHP去include_path里查找文件的速度,解析操作系统路径所需的时间会更少。
9、如果你想知道脚本开始执行(译注:即服务器端收到客户端请求)的时刻,使用$_SERVER[‘REQUEST_TIME’]要好于time()。
10、函数代替正则表达式完成相同功能。
11、str_replace函数比preg_replace函数快,但strtr函数的效率是str_replace函数的四倍。
12、如果一个字符串替换函数,可接受数组或字符作为参数,并且参数长度不太长,那么可以考虑额外写一段替换代码,使得每次传递参数是一个字符,而不是只写一行代码接受数组作为查询和替换的参数。
13、使用选择分支语句(译注:即switch case)好于使用多个if,else if语句。
14、用@屏蔽错误消息的做法非常低效,极其低效。
15、打开apache的mod_deflate模块,可以提高网页的浏览速度。
16、数据库连接当使用完毕时应关掉,不要用长连接。
17、错误消息代价昂贵。
18、在方法中递增局部变量,速度是最快的。几乎与在函数中调用局部变量的速度相当。
19、递增一个全局变量要比递增一个局部变量慢2倍。
20、递增一个对象属性(如:$this->prop++)要比递增一个局部变量慢3倍。
二、MYSQL数据提高执行效率的要点
1. 为查询缓存优化你的查询
大多数的MySQL服务器都开启了查询缓存。这是提高性最有效的方法之一,而且这是被MySQL的数据库引擎处理的。当有很多相同的查询被执行了多次的时候,这些查询结果会被放到一个缓存中,这样,后续的相同的查询就不用操作表而直接访问缓存结果了。
这里最主要的问题是,对于程序员来说,这个事情是很容易被忽略的。因为,我们某些查询语句会让MySQL不使用缓存。请看下面的示例:
// 查询缓存不开启 $r = mysql_query("SELECT username FROM user WHERE signup_date >= CURDATE()");
// 开启查询缓存 $today = date("Y-m-d");
$r = mysql_query("SELECT username FROM user WHERE signup_date >= '$today'");
上面两条SQL语句的差别就是 CURDATE() ,MySQL的查询缓存对这个函数不起作用。所以,像 NOW() 和 RAND() 或是其它的诸如此类的SQL函数都不会开启查询缓存,因为这些函数的返回是会不定的易变的。所以,你所需要的就是用一个变量来代替MySQL的函数,从而开启缓存。
2. EXPLAIN 你的 SELECT 查询
使用 EXPLAIN 关键字可以让你知道MySQL是如何处理你的SQL语句的。这可以帮你分析你的查询语句或是表结构的性能瓶颈。
EXPLAIN 的查询结果还会告诉你你的索引主键被如何利用的,你的数据表是如何被搜索和排序的……等等,等等。
挑一个你的SELECT语句(推荐挑选那个最复杂的,有多表联接的),把关键字EXPLAIN加到前面。你可以使用phpmyadmin来做这个事。然后,你会看到一张表格。下面的这个示例中,我们忘记加上了group_id索引,并且有表联接:
18. 越小的列会越快
对于大多数的数据库引擎来说,硬盘操作可能是最重大的瓶颈。所以,把你的数据变得紧凑会对这种情况非常有帮助,因为这减少了对硬盘的访问。
参看 MySQL 的文档 Storage Requirements 查看所有的数据类型。
如果一个表只会有几列罢了(比如说字典表,配置表),那么,我们就没有理由使用 INT 来做主键,使用 MEDIUMINT, SMALLINT 或是更小的 TINYINT 会更经济一些。如果你不需要记录时间,使用 DATE 要比 DATETIME 好得多。
当然,你也需要留够足够的扩展空间,不然,你日后来干这个事,你会死的很难看,参看Slashdot的例子(2009年11月06 日),一个简单的ALTER TABLE语句花了3个多小时,因为里面有一千六百万条数据。
19. 选择正确的存储引擎
在 MySQL 中有两个存储引擎 MyISAM 和 InnoDB,每个引擎都有利有弊。酷壳以前文章《MySQL: InnoDB 还是 MyISAM?》讨论和这个事情。
MyISAM 适合于一些需要大量查询的应用,但其对于有大量写操作并不是很好。甚至你只是需要update一个字段,整个表都会被锁起来,而别的进程,就算是读进程都无法操作直到读操作完成。另外,MyISAM 对于 SELECT COUNT(*) 这类的计算是超快无比的。
InnoDB 的趋势会是一个非常复杂的存储引擎,对于一些小的应用,它会比 MyISAM 还慢。他是它支持“行锁” ,于是在写操作比较多的时候,会更优秀。并且,他还支持更多的高级应用,比如:事务。
下面是MySQL的手册
* target=”_blank”MyISAM Storage Engine
* InnoDB Storage Engine
20. 使用一个对象关系映射器(Object Relational Mapper)
使用 ORM (Object Relational Mapper),你能够获得可靠的性能增涨。一个ORM可以做的所有事情,也能被手动的编写出来。但是,这需要一个高级专家。
ORM 的最重要的是“Lazy Loading”,也就是说,只有在需要的去取值的时候才会去真正的去做。但你也需要小心这种机制的副作用,因为这很有可能会因为要去创建很多很多小的查询反而会降低性能。
ORM 还可以把你的SQL语句打包成一个事务,这会比单独执行他们快得多得多。
② PHP的ZipArchive无法打开文件的错误,有谁遇到过的
③ PHP中“=>”的作用
这个在定义数组的时候,用来指定数组中下标和值的关系,例如:
$color=array('apple'=>'red', 'orange'=>'yellow');
echo $color['apple'];//输出red
④ PHP中文分词应用到搜索的例子
中文分词,首先对您输入的搜索关键字进行分词,然后数据库中本来就存在一个索引表,就像个词典,然后当你进行搜索的时候就用你的词去和那本字典对比,得到索引结果表,然后通过id类似于偏移地址,得到真正的数据源地址,反馈回来,这是我平时做搜索的方法,希望对你有用。顺便插播个小广告bbs.45net.cn。有时间捧个人场。O(∩_∩)O~
⑤ Thinkphp5.1微信小程序支付
研究了好几天,坑也遇到了,也网络了很久现在终于做完了,给大家分享出来,
我这个也是参考别人写的。有不明白的朋友可以问我
public function unifiedorder($order_no, $openid, $total_fee, $attach, $order_id, $user_id){
// 当前时间
$time = time();
// 生成随机字符串
$nonceStr = md5($time . $openid);
// API参数
$params = [
'appid' => $this->appid, //微信分配的小程序id
'attach' => $attach, //附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用。
'body' => '会员卡', //募捐描述
'mch_id' => $this->mchid, //微信支付分配的商户号
'nonce_str' => $nonceStr, //随机字符串,32位以内
'notify_url' => $this->notify_url, // base_url() . 'notice.php?s=/task/notify/order/wxapp_id/'.$wxapp_id, // 异步通知地址
'openid' => $openid, //用户标识;trade_type=JSAPI,此参数必传,用户在桥枯商户appid下的唯一标识。
'out_trade_no' => $order_no, 槐消码 //商户账单号
'spbill_create_ip' => \request()->ip(), //终端IP;支持IPV4和IPV6两种格式的IP地址。调用微信支付API的机器IP
'total_fee' => (int)$total_fee * 100, // 价格:单位分 // 价格:单位分
'trade_type' => 'JSAPI', //交易类型
];
// 生成签名
$params['sign'] = $this->makeSign($params); //这个地方最坑,需要的是配置 1、appid和商户号必须是绑定的状态
// 请求API
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$result = $this->post($url, $this->toXml($params));
$prepay = $this->fromXml($result);
//添加preapay_id
$data = [
'user_id' => $user_id,
'order_id'铅哪 => $order_id,
'attach' => json_encode($attach),
'prepay_id' => $prepay['prepay_id'],
];
(new AppleWxPrepay())->addInfo($data);
// 请求失败
if ($prepay['return_code'] === 'FAIL') {
return [API_CODE_NAME => 2000004, API_MSG_NAME => $prepay['return_msg']];
}
if ($prepay['result_code'] === 'FAIL') {
return [API_CODE_NAME => 2000004, API_MSG_NAME => $prepay['err_code_des']];
}
// 生成 nonce_str 供前端使用
$paySign = $this->makePaySign($params['nonce_str'], $prepay['prepay_id'], $time);
return [
'prepay_id' => $prepay['prepay_id'],
'nonceStr' => $nonceStr,
'timeStamp' => (string)$time,
'paySign' => $paySign
];
}
/**
* 生成签名
* @param $values
* @return string 本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值
*/
private function makeSign($values)
{
//签名步骤一:按字典序排序参数
ksort($values);
$string = $this->toUrlParams($values);
//签名步骤二:在string后加入KEY
$string = $string . '&key=' . $this->apikey;
//签名步骤三:MD5加密
$string = md5($string);
//签名步骤四:所有字符转为大写
$result = strtoupper($string);
return $result;
}
/**
* 格式化参数格式化成url参数
* @param $values
* @return string
*/
private function toUrlParams($values)
{
$buff = '';
foreach ($values as $k => $v) {
if ($k != 'sign' && $v != '' && !is_array($v)) {
$buff .= $k . '=' . $v . '&';
}
}
return trim($buff, '&');
}
/**
* 模拟POST请求
* @param $url
* @param array $data
* @param bool $useCert
* @param array $sslCert
* @return mixed
*/
public function post($url, $data = [], $useCert = false, $sslCert = [])
{
$header = [
'Content-type: application/json; charset=UTF8'
];
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_POST, TRUE);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
if ($useCert == true) {
// 设置证书:cert 与 key 分别属于两个.pem文件
curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'PEM');
curl_setopt($curl, CURLOPT_SSLCERT, $sslCert['certPem']);
curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM');
curl_setopt($curl, CURLOPT_SSLKEY, $sslCert['keyPem']);
}
$result = curl_exec($curl);
curl_close($curl);
return $result;
}
/**
* 输出xml字符
* @param $values
* @return bool|string
*/
private function toXml($values)
{
if (!is_array($values) || count($values) <= 0) {
return false;
}
$xml = "<xml>";
foreach ($values as $key => $val) {
if (is_numeric($val)) {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
} else {
$xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
}
}
$xml .= "</xml>";
return $xml;
}
/**
* 将xml转为array
* @param $xml
* @return mixed
*/
private function fromXml($xml)
{
// 禁止引用外部xml实体
libxml_disable_entity_loader(true);
return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
}
/**
* 生成paySign
* @param $nonceStr
* @param $prepay_id
* @param $timeStamp
* @return string
*/
private function makePaySign($nonceStr, $prepay_id, $timeStamp)
{
$data = [
'appId' => $this->appid,
'nonceStr' => $nonceStr,
'package' => 'prepay_id=' . $prepay_id,
'signType' => 'MD5',
'timeStamp' => $timeStamp,
];
// 签名步骤一:按字典序排序参数
ksort($data);
$string = $this->toUrlParams($data);
// 签名步骤二:在string后加入KEY
$string = $string . '&key=' . $this->apikey;
// 签名步骤三:MD5加密
$string = md5($string);
// 签名步骤四:所有字符转为大写
$result = strtoupper($string);
return $result;
}
/*********************************微信回调**********************/
public function getNotify()
{
if (!$xml = file_get_contents('php://input')) {
$this->returnCode(50000001, 'Not found DATA');
}
// 将服务器返回的XML数据转化为数组
$data = $this->fromXml($xml);
$payLog = new ApplePayLog();
// 记录日志
$payLog->addInfo(['content'=>json_encode($xml)]);
$payLog->addInfo(['content'=>json_encode($data)]);
// 实例化账单模型
$OrderModel = new AppleOrder();
// 账单信息
$orderInfo = $OrderModel->getInfo(['id'=>$data['attach']],'*');
if (empty($orderInfo)) {
$this->returnCode(50000001, '账单不存在');
}
if($orderInfo['pay_status'] != 1 || !empty($orderInfo['pay_time'])){
$this->returnCode(50000001,'订单已支付,请勿再次支付');
}
// 保存微信服务器返回的签名sign
$dataSign = $data['sign'];
$return_code = $data['return_code'];
$result_code = $data['result_code'];
$data['body'] = '会员卡';
$data['spbill_create_ip'] = \request()->ip();
$data['notify_url'] = $this->notify_url;
// sign 与 s 参数 不参与签名算法
unset($data['sign']);
unset($data['transaction_id']);
unset($data['coupon_id']);
unset($data['coupon_type']);
unset($data['coupon_count']);
unset($data['coupon_fee']);
unset($data['time_end']);
unset($data['return_code']);
unset($data['result_code']);
unset($data['is_subscribe']);
unset($data['fee_type']);
unset($data['bank_type']);
unset($data['bank_type']);
// 生成签名
$sign = $this->makeSign($data);
// 判断签名是否正确 判断支付状态
if (($sign === $dataSign) && ($return_code == 'SUCCESS') && ($result_code == 'SUCCESS')) {
$OrderModel->startTrans();
try {
// 账单支付成功业务处理
$appleOrderInfo = $OrderModel->where(['id'=>$orderInfo['id']])->lock(true)->find();
$result = $appleOrderInfo->addInfo(['pay_status'=>2,'pay_time'=>time()],['id'=>$orderInfo['id']]);
if(!$result){
$OrderModel->rollback();
$this->returnCode(5000003, '修改订单失败,失败原因:'.$OrderModel->getError());
}
$appleUserModel = new AppleUser();
$appleUserInfo = $appleUserModel->where(['openid'=>$orderInfo['openid']])->lock(true)->find();
$appleUser = $appleUserInfo->where(['openid'=>$orderInfo['openid']])->setInc('moxibustion',$orderInfo['moxibustion']);
if(!$appleUser){
$OrderModel->rollback();
$this->returnCode(5000003, '添加会员针灸次数失败,失败原因:'.$appleUserModel->getError());
}
}catch (\Exception $exception){
$OrderModel->rollback();
$this->returnCode(5000003, '操作失败,失败原因:'.$exception->getMessage());
}
$OrderModel->commit();
// 返回状态
die(json(['code'=>0,'支付成功']));
}
// 返回状态
$this->returnCode(2000003, '签名失败');
}