① 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, '簽名失敗');
}