[轉載]PHP 和 MySQL 開發的 8 個技巧 | Vixual
轉載自:中文 PHP 資訊站
LAMP 架構的網站,我以前注重的多是安裝/配置方面的,講述開發的相對較少,因為自己從事開發也少。本文的原文當然也來自:
看了以後,頗有啟發,以前開發中遇到的一些問題,迎刃而解。所以翻譯出來和大家共用。
1. PHP 中陣列的使用
在操作資料庫時,使用關聯陣列(associatively-indexed arrays)十分有幫助,下面我們看一個基本的數位格式的陣列遍歷:
<?php $temp[0] = “richmond"; $temp[1] = “tigers"; $temp[2] = “premiers";for($x=0;$x<count($temp);$x++){echo $temp[$x];echo " “; } ?>
然而另外一種更加節省代碼的方式是:
<?php $temp = array(“richmond", “tigers", “premiers"); foreach ($temp as $element){echo “$element “; } ?>
foreach 還能輸出文字下標:
<?php $temp = array(“club" => “richmond", “nickname" =>"tigers", “aim" => “premiers"); foreach ($temp as $key => $value){ echo “$key : $value “; } ?>
PHP 手冊中描述了大約 50 個用於處理陣列的函數。
2. 在 PHP 字串中加入變數
這個很簡單的:
<?php $temp = “hello" echo “$temp world"; ?>
但是需要說明的是,儘管下面的例子沒有錯誤:
<?php $temp = array(“one" => 1, “two" => 2); // 輸出:: The first element is 1 echo “The first element is $temp[one]."; ?>
但是如果後面那個 echo 語句沒有雙引號引起來的話,就要報錯,因此建議使用花括弧:
<?php $temp = array(“one" => 1, “two" => 2); echo “The first element is {$temp[“one"]}."; ?>
3. 採用關聯陣列存取查詢結果
看下面的例子:
<?php $connection = mysql_connect(“localhost", “albert", “shhh"); mysql_select_db(“winestore", $connection);$result = mysql_query(“SELECT cust_id, surname, firstname FROM customer", $connection);while ($row = mysql_fetch_array($result)){echo “ID:\t{$row[“cust_id"]}\n";echo “Surname\t{$row[“surname"]}\n";echo “First name:\t{$row[“firstname"]}\n\n"; } ?>
函數 mysql_fetch_array() 把查詢結果的一行放入陣列,可以同時用兩種方式引用,例如 cust_id 可以同時用下面兩種方式:$row[“cust_id"] 或者$row[0] 。顯然,前者的可讀性要比後者好多了。 在多表連查中,如果兩個列名字一樣,最好用別名分開:
SELECT winery.name AS wname, region.name AS rname FROM winery, region WHERE winery.region_id = region.region_id;
列名的引用為:$row[“wname"] 和 $row[“rname"]。
在指定表名和列名的情況下,只引用列名:
SELECT winery.region_id FROM winery
列名的引用為: $row[“region_id"]。
聚集函數的引用就是引用名:
SELECT count(*) FROM customer;
列名的引用為: $row[“count(*)"]。
4. 注意常見的 PHP bug
常見的 PHP 糾錯問題是:
No page rendered by the Web browser when much more is expected
A pop-up dialog stating that the “Document Contains No Data"
A partial page when more is expected
出現這些情況的大多數原因並不在於腳本的邏輯,而是 HTML 中存在的 bug 或者腳本生成的 HTML 的 bug 。例如缺少類似 </table>, </form>, </frame> 之類的關閉 Tag,頁面就不能刷新。解決這個問題的辦法就是,查看 HTML 的源代碼。
對於複雜的,不能查到原因的頁面,可以通過 W3C 的頁面校驗程式 http://validator.w3.org/ 來分析。
如果沒有定義變數,或者變數定義錯誤也會讓程式變得古怪。例如下面的閉環:
<?php for($counter=0; $counter<10; $Counter++){myFunction(); ?>
變數 $Counter 在增加,而 $counter 永遠小於 10。這類錯誤一般都能通過設置較高的錯誤報告級別來找到:
<?php error_reporting(E_ALL);for($counter=0; $counter<10; $Counter++){myFunction(); ?>
5. 採用 header() 函數處理單部件查詢
在很多 Web 資料庫應用中,一些功能往往讓用戶點擊一個連接後,繼續停留在當前頁面,這樣的工作我叫它"單部件查詢"。
下面是一個叫做 calling.php 的腳本:
<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.0 Transitional//EN" “http://www.w3.org/TR/html4/loose.dtd"> <html> <head><title>Calling page example</title> </head> <body><a href="action.php">Click here!</a> </body> </html>
當用戶點擊上面的連接時,就去調用 action.php。下面是 action.php 的源碼:
<?php // 重定向 header(“Location: $HTTP_REFERER"); exit; ?>
這裏有兩個常見的錯誤需要提醒一下:
調用 header() 函數後要包含一個 exit 語句讓腳本停止,否則後續的腳本可能會在頭發送前輸出。
header() 函數常見的一個錯誤是:
Warning: Cannot add header information – headers already sent…
header() 函數只能在 HTML 輸出之前被調用,因此你需要檢查 php 前面可能存在的空行,空格等等。
6. reload 的問題及其解決
我以前在寫 PHP 程式時,經常碰到頁面刷新時,資料庫多處理一次的情況。
我們來看 addcust.php:
<?php $query = “INSERT INTO customer SET surname = $surname, firstname = $firstname"; $connection = mysql_connect(“localhost", “fred", “shhh"); mysql_select_db(“winestore", $connection); $result = mysql_query($query, $connection); ?> <!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.0 Transitional//EN" “http://www.w3.org/TR/html4/loose.dtd"> <html> <head><title>Customer insert</title> </head> <body> I’ve inserted the customer for you. </body> </html> ?>
假設我們用下面的連接使用這個程式:
http://www.freelamp.com/addcust.php?surname=Smith&;firstname=Fred
如果這個請求只提交一次,OK ,不會有問題,但是如果多次刷新,你就會有多條記錄插入。
這個問題可以通過 header() 函數解決:下面是新版本的 addcust.php:
<?php $query = “INSERT INTO customer SET surname = $surname, firstname = $firstname"; $connection = mysql_connect(“localhost", “fred", “shhh"); mysql_select_db(“winestore", $connection); $result = mysql_query($query, $connection); header(“Location: cust_receipt.php"); ?>
這個腳本把瀏覽器重定向到一個新的頁面:cust_receipt.php:
<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.0 Transitional//EN" “http://www.w3.org/TR/html4/loose.dtd"> <html> <head><title>Customer insert</title> </head> <body> I’ve inserted the customer for you. </body> </html>
這樣,原來的頁面繼續刷新也沒有副作用了。
7. 巧用鎖機制來提高應用性能
如果我們要緊急運行一個報表,那麼,我們可以對表加寫鎖,防治別人讀寫,來提高對這個表的處理速度。
8. 用 mysql_unbuffered_query() 開發快速的腳本
這個函數能用來替換 mysql_query() 函數,主要的區別就是 mysql_unbuffered_query() 執行完查詢後馬上返回,不需要等待或者對資料庫加鎖。
但是返回的行數不能用mysql_num_rows() 函數來檢查,因為輸出的結果集大小未知。
相關
[轉載]軟體工程師縮短工時
轉載自: CNet 微軟軟體設計工程師Adam Barr最近常和家人共用晚餐。但以前可不是如此。90…
2005-04-06
在「Coding」中
[轉載]PHP 正規表達式基本語法
轉載自: 中文 PHP 資訊站 首先讓我們看兩個特殊的符號: ^ 和 $。他們的作用是分別指出一個字…
2005-01-22
在「Coding」中
☺
Deconstruction of a VBA Code Module – CodeProject
When working with VBA, a useful tool to have is a module which creates extracts of your work. If you produce frameworks, a complete listing of all components and procedures could prove useful in maintaining consistency in the model. Since the incorporation of the Visual Basic Editor into the Microsoft Office application suite, it is possible to have both.
This article is intended to build on the extensibility knowledge base with a focus on deconstructing a VBA code module. The target being a report of all procedures in the active VBA project. Included with this article is a standard VBA module which employs the deconstruction techniques and is a complete extract and reporting package.
Please note that in order to use the codebase in this article, any targeted Office application must support theVBE interface.
Visual Basic Editor (VBE)
The Visual Basic Editor is an interface which is used to used to create, modify, and maintain Visual Basic for Applications objects. The majority of Microsoft Office applications include a built-in VBE interface which is used to access the underlying Microsoft Visual Basic for Applications Extensibility library (VBIDE). The interface is VBE, its implementation is VBIDE, and the code is VBA.
At runtime, an instance of VBIDE is automatically made available through the VBE property of the Application object. Additional type libraries are not required to use the property or the interface it exposes. The only requirement being that the target Office application supports the interface.
As a result, this project does not early bind to the extensibility type library. All extensibility objects are dimensioned as Object and any required constants have been manually re-created in the module included with this article.
With the required objects already in place, the focus can shift to the deconstruction of a VBA code module and the VBE CodeModule object.
CodeModule Object
A VBComponent is a container which enables differentiation between code objects in a VBA project. A component can be a standard module, a class module, a user form, or a document. Each VBComponent contains one code module and the CodeModule object provides access to it.
Combine the CodeModule object with the capabilities of VBA, and the two become a powerful editor. As with most editors, lines can be inserted, deleted, and replaced. The object includes find-find next functionality and lines (or blocks of lines) can be retrieved. In the scope of this project, lines are indexed, counted, and sometimes retrieved.
The CodeModule object resolves a VBA module by lines. The Lines
collection begins at line 1 and continues untilCountOfLines
is reached, the last line in a module. Any single line or blocks of lines can be retrieved using the collection.
A module can also be separated into declarations and procedures. The declarations section begins at line 1 and continues until it reaches CountOfDeclarationLines
, the last non-procedural declaration in a module. The procedures section begins atCountOfDeclarationLines + 1
and continues until CountOfLines
is reached.
If there are zero procedures in a module, then all lines belong to the declarations section. If there are zero declarations in a module, then all lines belong to the procedures section, providing there are procedures.
The following example will extract all of the code in the active project and display it in the immediate window. The declarations and procedures have been provided their own iterators to enable working with a module in sections. It is also using the Lines collection to display the single line with which the index represents.
Hide Copy Code
PublicSubListCode()DimComponentAsObjectDimIndexAsLongForEachComponentInApplication.VBE.ActiveVBProject.VBComponentsWithComponent.CodeModuleForIndex =1To .CountOfDeclarationLinesDebug.Print .Lines(Index, 1)Next IndexFor Index = .CountOfDeclarationLines + 1 To .CountOfLinesDebug.Print .Lines(Index, 1)Next IndexEnd WithNext ComponentEnd Sub
Procedure Blocks
A procedure is defined by a developer. The Kind of procedure available is built into the programming language. The CodeModule object recognizes Property Get
, Property Let
, and Property Set
statements as procedure Kind. It also recognizesSub
and Function
but does not differentiate between the two, it collectively defines them as Proc
.
To the CodeModule object, a procedure is a block of lines which has location and length. It defines location asProcStartLine
and length as ProcCountLines
. It also defines ProcBodyLine
which is the location of the procedural declaration within the block.
ProcStartLine
and ProcBodyLine
are line numbers calculated from Line 1. ProcCountLines
is the line count betweenProcStartLine
and ProcCountLines
, inclusive.
A procedure includes all whitespace and comments above its declaration and ends with its terminating block. The exception being the last procedure in a module as it also includes all whitespace and comments to the end of the module.
The location and length properties can be used to index procedures, but to use the properties, a procedureName
and procedureKind
are required.
In this project, theProcOfLine
property is used to determine a procedure Name and Kind at a given line number. To useProcOfLine
, a line number and the name of a long variable must be supplied.ProcOfLine
will examine the line and return the name of the procedure which owns it. It will also fill the long variable with the kind of procedure it is.
Once a procedure Name and Kind have been determined, the location and length properties can be used to index into a procedure, or through all the procedures in a module.
In the following example, Index is seeded toCountOfDeclarationLines + 1
, the beginning of the procedures section. A call toProcOfLine
using the Index fills both the Name and Kind variable values. Having the two values enablesProcStartLine
andProcCountLines
to calculate the end of the current procedure (ProcStartLine
+ProcCountLines
) and then Index to the beginning of the next procedure (+1
).
Hide Copy Code
PublicSubListNames()DimComponentAsObjectDimNameAsStringDimKindAsLongDimIndexAsLongForEachComponentInApplication.VBE.ActiveVBProject.VBComponentsWithComponent.CodeModuleIndex = .CountOfDeclarationLines +1DoWhile Index < .CountOfLinesName = .ProcOfLine(Index, Kind)Debug.Print Component.Name & “." & NameIndex = .ProcStartLine(Name, Kind) + .ProcCountLines(Name, Kind) + 1LoopEnd WithNext ComponentEnd Sub
ListNames
will display all procedures in the active project by module. However, the list could contain duplicates within the individual modules. The duplications belong to properties which have both a Get
and a Let
or Set
defined. To produce a unique list of procedures in a module, the procedure Kind
should be incorporated into a result set.
Data Transformations
In this project, data is converted from value to meaningful name for reporting purposes. Constant values have been extracted from the VBIDE library and are used to define the component type, procedure kind, and reference kind. With the exception of the procedure kind, vanilla case statements are employed to transform a defined object from value to name.
Hide Copy Code
Private Const vbext_ct_ActiveXDesigner As Long = 11 Private Const vbext_ct_ClassModule As Long = 2 Private Const vbext_ct_Document As Long = 100 Private Const vbext_ct_MSForm As Long = 3 Private Const vbext_ct_StdModule As Long = 1Private Const vbext_pk_Get As Long = 3 Private Const vbext_pk_Let As Long = 1 Private Const vbext_pk_Set As Long = 2 Private Const vbext_pk_Proc As Long = 0Private Const vbext_rk_Project As Long = 1 Private Const vbext_rk_TypeLib As Long = 0
As you might remember from the procedures discussion, the CodeModule object does not differentiate between Sub
andFunction
. The object collectively defines them as Proc
, or actually, VBIDE.vbext_ProcKind.vbext_pk_Proc
. If the distinction between Sub
and Function
is required, then a workaround needs to be employed.
The following example performs a data transformation from vbext_ProcKind
to a meaningful name. The function is passed a long value of vbext_ProcKind enum
and the declaration text from ProcBodyLine
. A best guess workaround checks if the declaration text contains the word “Function-Space
“. If a match is made then it assumes Function
and if not, Sub
.
Hide Copy Code
Public Function GetProcKind(Kind As Long, Declaration As String) As StringSelect Case KindCase vbext_pk_GetGetProcKind = “Get"Case vbext_pk_LetGetProcKind = “Let"Case vbext_pk_SetGetProcKind = “Set"Case vbext_pk_ProcIf InStr(1, Declaration, “Function “, vbBinaryCompare) > 0 ThenGetProcKind = “Func"ElseGetProcKind = “Sub"End IfCase ElseGetProcKind = “Undefined"End SelectEnd Function
Using best guess as formatted has been successful, however, rarely do I comment procedural declarations in-line. But being developers and knowing what to look for makes snippets like best guess easy to change.
Procedure Report
At this point, it seems appropriate to end this brief discussion of the CodeModule
object with a procedure report. This final example produces a unique list of all procedures in the active project along with a line count. The line count is a simple calculation of all lines between a procedural declaration and its terminating block.
The example also employs the GetProcKind
transformation and begins to condense variable names. If you understand this bit of code, then you’ll be well on the way to writing your own extensibility reports. I’ll leave it with you to fill in the blanks.
HideShrink
Copy Code
PublicSubReportProcNames()DimComponentAsObjectDimNameAsStringDimKindAsLongDimStartAsLongDimBodyAsLongDimLengthAsLongDimBodyLinesAsLongDimDeclarationAsStringDimProcedureTypeAsStringDimIndexAsLongForEachComponentInApplication.VBE.ActiveVBProject.VBComponentsWithComponent.CodeModuleIndex = .CountOfDeclarationLines +1DoWhile Index < .CountOfLinesName = .ProcOfLine(Index, Kind)Start = .ProcStartLine(Name, Kind)Body = .ProcBodyLine(Name, Kind)Length = .ProcCountLines(Name, Kind)BodyLines = Length – (Body – Start)Declaration = Trim(.Lines(Body, 1))ProcedureType = GetProcKind(Kind, Declaration)Debug.Print Component.Name & “." & Name & “." & _ProcedureType & “." & CStr(BodyLines)Index = Start + Length + 1LoopEnd WithNext ComponentEnd Sub
MProject Setup
MProject is a standard VBA module that is available with this article. It contains a single public procedure named ExportProject which is used to extract all of the code in the active VBA project.
To use MProject, the minimum requirement is Office 2003 or later. Also, any targeted Office application must support the VBE interface. (see the support section for details)
To include MProject in your office application, please use the following steps…
Create a folder
Move your office project into the folder
Import the MProject module into the office project
Compile and save the project
It should be considered mandatory to move the office project to its own folder. A call to ExportProject automatically creates a subfolder structure named “VBA" at the current location of the office project file. The VBA folder will contain both a Code and Report subfolder as shown in the following image:
At the beginning of each extract run, the Code and Report folders are either created or cleared of all files. Components are then extracted to the Code folder. If a workbook report is requested, it is saved to the Report folder. ExportProject does not alter any other folders or files.
ExportProject Usage
To use ExportProject is easy. Type ExportProject in the immediate window and press enter. An immediate window report should appear detailing the results of the run. The report displays the VBA base folder location and ten summary values which seem the most useful.
Hide Copy Code
ExportProject BaseFolderC:\Users\Mark Regal\Desktop\MyOfficeProject\VBA Extracts6 References5 Components5 Procedures11 UniqueNames11 Declarations41 CodeLines250 Comments235 TotalCode291 TotalLines526 Done…
Typically, the extract and component counts will be different. The MProject module is always extracted with the active project, however, it is not included in the counts and calculations unless asked. (see the syntax section for details)
The summary definitions are as follows…
BaseFolder
VBA folder for the current office project
Extracts
Count of all code module extracts
References
Count of all project and type library references
Components
Count of all components used in calculations and counts
Procedures
Count of all procedures
UniqueNames
Count of unique procedure names from all modules
Declarations
Count of all declarations
CodeLines
Count of all lines of code
Comments
Count of all comments and whitespace
TotalCode
Sum of CodeLines + Declarations
TotalLines
Sum of CodeLines + Declarations + Comments
Please note that it should be considered a common practice to selectively comment (in or out) report lines as needed. The report lines are simple Debug.Print statements and exist in the MProject.ExportProject procedure.
Workbook Report
When requested, ExportProject will create an Excel workbook at the end of an extract run. The workbook contains detailed views of the procedures, components, and references in the active project. It also includes a worksheet of the extracted components and their file and path information.
As mentioned in MProject setup, the workbook is always saved to the Report folder in the VBA folder structure. If a workbook is not requested, then an empty Report folder should be expected as it is cleared at the beginning of every extract run.
It is important to note that both the workbook and Immediate report use the same data, displayed at varying levels of detail. Code lines and declarations are counted as actual lines of code. Comments and whitespace are counted as comments, and the total line counts are summaries of the two.
ExportProject Syntax
ExportProject([DisplayWorkbook [,OpenBaseFolder [,ExcludeModule]]])
DisplayWorkbook Optional Boolean value
True
displays an Excel workbook report at the completion of a successful run
False
(or no value) does not create a report
The default value is False
OpenBaseFolder Optional Boolean value
True
opens the base extract folder at completion of a successful run
False
(or no value) and no action is taken
The default value is False
ExcludeModule Optional Boolean value
True
(or no value) will exclude MProject in all counts and calculations
False
will include MProject in all counts and calculations
MProject is always part of the code extract regardless of this setting
The default value isTrue
*
Please note that if theMProject
module is renamed, the value of theModule_Name
constant must be changed to match the new name.
Version History
Version
Release Date
2.0
2013.11.12
1.0
2013.08.20
Release Notes – Version 2.0
Added a unique procedure names worksheet
Added a scope column to the procedures worksheet
Reformatted the procedures worksheet
Reformatted messaging
Release Notes – Version 1.0
Office VBE Support
In order to use the codebase in this project, any targeted Office application must support the VBE interface. The easy way to determine if an Office application supports the interface is to use the following steps…
Create a new instance of any Office application to be tested
Open the VBA IDE window of the new instance
Navigate to the immediate window and type Application.VBE
TheIntelliSensepopup window should appear and if VBE is included in the list, then there is a good chance that this project will work in that application and version. If VBE does not appear in the list, then this project will not work in the tested version of the application.
Troubleshooting Tips
During an extract run, any error will generate a detailed message and the program will exit gracefully. The error message should provide enough information to determine a root cause. Once the error has been resolved, simply re-run ExportProject.
A few tips which might prove useful…
Make sure the project compiles without errors
Close all extract files and the workbook report before an extract run
Verify read-write access is available to the project folder
If required, confirm “Trust access to the VBA project object model" is enabled. In Office 2003, it appears as a Macro Security setting. In Office 2007 and later, it is part of the Trust Center settings. For more information, seeMicrosoft Knowledge Base article KB282830.
Project References
I’ve been coding in the VBA language since the day it was made available, but be that as it may, there are plenty of informative sites which can improve on the discussion of the CodeModule object. Microsoft is beginning to shine with its on-line documentation and is a favorite of mine.
The following sites have been used as references for this article:
Final Thoughts
Above all else, two key concepts should be taken from this article. One, the CodeModule object is an editor of VBA code, and two, it can be used to data mine a VBA code module at runtime. With data mining and a bit of ingenuity, many advanced coding techniques are possible. Techniques such as parsing enumerations, and much more.
VBA has always been a challenging language as it is object oriented lite. But it never ceases to amaze how easy it is to use, and how useful it actually turned out to be.
☺