Defensive Programming in PHP(PHP中的防禦性編程)

覺得這篇文章寫得很不錯 不關乎php覺得其他的語言也是針對的,看完這篇文章有所收穫

What Does “Defensive Programming” Mean?

Defensive programming, simply put, is programming with the intent to anticipate likely failure points. The goal is to circumvent those likely problems before they occur. You see the problem, right? There’s something inherently difficult with the advice “expect the unexpected” and it’s made many times worse when one alters it to “expect the unexpected and try to prevent it”.

Let’s look at some practical examples.

Conditional Statements

This is one of the easiest places to program defensively, and one where it’s easiest to be complacent. In many cases while programming in PHP, you simply won’t need an “else” case.

Hypothetically, you are working on a function and need a conditional. You only have three possible states for your particular variable at this point – and you have those covered in a block like this:

if($var == a){ }
else if($var == b){ }
else if($var == c){ }

There are no other possibilities, you say, and you move on with your code. Let me stop you there, though. I know that you know there are no other possibilities. And I believe you. But sometimes (unexpected) things happen. We forget about something. We look over mistakes. We end up reusing a bit of code outside of its originally intended scope. And all of a sudden we have leaking and sometimes silent error states because there’s no catch here. Make use of else blocks. Make use of default in switches. Use them to return or log an error so that you’re aware of what’s happened, should it ever happen. It may be an extra couple of lines of code, but it’s worth it when something happens that you did not expect.

Never Trust User Input

Have you heard this statement before? Most programmers have. It is a bit of a vague, generalized thing to say, granted. But it’s true. You should never trust user input. This does not mean that you assume that all users are crazed hackers out to destroy your application with a single set of well crafted commands. There is no need for paranoia. But, you should assume that users don’t know your code. They don’t know what parameters you need filled or how long the input can be. They don’t know what file types they can upload (even if the app tells them) or what size. And occasionally, they are a bot or a hacker and they are going to be trying to run scripts in their inputs. Sometimes even from inputs behind a login wall. How do you know when you can trust things like authentication or captchas to provide a safe barrier before users arrive at input forms?

The answer: Never.

If you never trust user input, then you never have a breach because you trusted user input. See? So always validate your input, and always ensure that you’re using appropriate techniques when handling data, especially when storing it in the database or retrieving it for display. For that matter – don’t trust input at all, even when from somewhere besides your users – input validation is always your friend. Check outSurvive the Deep End: PHP Security and look into using a validation library.

Assumptions About Your Code

Don’t assume anything. If the previous two topics teach us anything, it’s that we should not make any assumptions. As programmers, especially when focusing on a single project for too long, we begin to assume a lot. We begin to assume that the user knows some of the things we know. Not necessarily technical details, but functional details about the program. We assume that the user will know how big files can be because… we already know that fact. Or that they’ll know that in order for the mailing script to… but no, they have no idea about any of that. This can sometimes matter more for front-end work, but obviously you still deal with user behavior and user input in the back-end as well, so it’s worth thinking about.

Another staggering assumption that many programmers make is the assumption of the obvious nature of our functions, classes, or whatever other bit of code we’re working on at any given time. A defensive programmer will try to think carefully about not only normal documentation and describing what a bit of functionality does – but they will also document any assumptions they are making about input, parameters, use cases, or any number of other similar things. Because we are all humans, and we sometimes forget things later. We also will all most likely end up with someone maintaining, extending, or replacing our code someday. If nothing else, recall that programming is happening in a world full of technological changes. If your application is still around in several years, it may need to be updated to a newer version of PHP and lose some of its functionality, or any number of components that it interacts with may change and necessitate changes in your own code. It is very difficult to predict these things, so good comments and documentation are very important.

Tunnel Vision

Another thing that can cause us to both forget good commenting practices as well as standards is tunnel vision. Tunnel vision happens a lot to programmers. You know the feeling. You’re solving a problem, you’re in the groove. You’re feeling isolated in your own little world, with your music (or lack thereof) and you’re just coding and all of a sudden two hours have passed since you last checked the clock and you realize that you’ve written countless lines of code without any comments. It happens to all of us at one time or another, but the important thing is to, at some point, catch that and add some where appropriate.

Consistency in Syntax and Naming

Consistency is a bit of a grey area – that delves a bit more into coding standards and the like, but it is relevant to defensive programming. In PHP, there are standards that can be followed to streamline your code for others who might view it, or for your own future use. But often, no one is actually making you code to standard. However, whether you’re coding to some set of standards or not, you should at very least be internally consistent – because it will make you less error prone. This applies especially to small syntax errors that take an aggravating amount of time to return to and fix after being caught. If you always use the same spacing, the same formats and syntax, naming conventions, etc., than you are less likely to make a mistake resulting in your misreading of your own code. You are also more likely to be able to quickly scan and find things that you need to find.

Conclusion

Beyond user behaviors and actions, don’t assume anything in general about your program. Assumptions are one of the biggest enemies of a defensive programmer. Don’t assume you won’t need that default case or else statement. Don’t avoid creating appropriate user error messages, alerts, logs, and whatever else you need just because you assume they won’t be needed. Your assumptions are often right – but we do not care about that. What we care about are the times that they are wrong. Always plan as though you may need to return to your code in a few hours, weeks, months or even years, or that someone else will – and document it accordingly. Don’t assume it will never need to be updated, extended, or maintained. That’s naive at best, and negligent in more cases than not. Sometimes just keeping the idea of defensive programming in the back of your mind can help you to estimate, plan, and program more effectively and more safely.

譯文:

防禦性編程是什麼意思

防禦性編程,簡單的說,就是在編程的時候有目的地預測可能的故障點。目的是在那些可能發生的問題發生前解決它們。你看見了問題,對吧?預測意料之外的事情本來就有內在的難度,當你想要預測意料之外的事情並且解決它就更是難上了好幾倍。

下面我們看幾個實際的例子。

條件語句

這是最容易進行防禦性編程的地方之一,也是最容易滿足的地方。在用PHP編程的許多情況下你不會需要“else”。

假設,你在寫一個函數並且需要一個條件語句。在這裏,你只需要爲你特定的變量使用三個條件語句如下:

if($var == a){ }
else if($var == b){ }
else if($var == c){ }

沒有其他可能性了,你說,並且繼續碼代碼。但是,讓我們在這裏停一下。我知道你知道這裏沒有其他可能性了。並且我相信你。但有時候(不可預測的)情況會發生。我們忘掉了一些情況。我們檢查錯誤。我們最終重用了一些代碼,超出了原本的預定範圍。突然我們有了泄露錯誤或者有時候是靜默的錯誤狀態,因爲我們沒有使用catch。使用else代碼塊。在使用switch時要使用default。用它們來返回或者記錄錯誤,這樣你才知道發生了什麼(如果發生了的話)。雖然會多用兩行代碼,但當一些你無法預測的事情發生時,這是值得的。

絕不相信用戶輸入

你以前有沒有聽說過這個說法?大多數程序員聽過。這有一點含糊,通俗點講,理所當然。但它是真理。你絕不應該相信用戶輸入。這不是說你假設所有用戶是瘋狂的黑客,他們使用一些精心設計的命令來摧毀你的應用。沒有必要妄想。但是,你應該假設用戶不知道你的代碼,他們不知道你需要填寫什麼參數,或者參數應該多長。他們不知道什麼文件類型或者什麼大小能上傳(即使應用告訴了他們)。偶爾他們會是機器或者黑客並且他們希望在他們的輸入中運行腳本,有時候甚至是在登陸後的輸入中。你怎麼知道你能相信認證或者驗證碼能在用戶輸入之前提供一個安全的堡壘?

答案:絕不。

你絕不相信用戶輸入。如果你信任的用戶輸入,那麼你永遠不會有一個突破。明白了嗎?所以總是要評估你的輸入,一定要保證你在處理數據尤其是要存入數據庫或者要把它展示出來時使用了合適的技術。因此 – 絕不相信輸入,即使來自不是用戶的輸入的地方 – 輸入驗證永遠是你的朋友。看看Survive the Deep End: PHP Security 並且使用 validation library.吧。

對你的代碼的假設

不要假設任何事情。如果前兩個主題教會我們一些事情的話,那就是我們不應該做任何假設。作爲程序員,尤其是致力於一個項目太久後,我們開始做很多假設。我們假設用戶知道一些我們知道的事情。不一定是技術細節,也可以是程序的功能性細節。我們假設用戶知道文件能有多大因爲。。。我們已經知道。或者他們知道爲了讓郵件腳本。。。但事實不是,他們不知道以上任何東西。這好像更多的是前端的工作,但明顯的是你在後端仍然要處理用戶行爲和用戶輸入,所以值得好好想想。

另一個許多程序員都會做的驚人的假設是我們在任何時候對於我們的函數,類或者其它代碼段的明顯的功能屬性。一個具有防禦性的程序員會仔細考慮的不僅僅是用一般的文檔來描述函數是幹什麼的——他們也將寫下他們對輸入,參數,用例,或任何其他類似的東西做出的任何假設。因爲我們都是人,我們過一段時間會忘掉一些事。我們最後也很可能會面臨其他人維護,擴展或者替換我們的代碼。如果沒有別的,回想一下,編程是發生在一個充滿技術變革的世界裏。如果你的應用仍然能使用幾年,可能會升級PHP版本並且失去一些功能,或者一些你自己代碼裏面具有交互的組件之間需要改變。預測這些是很困難的,所以好的註釋和文檔是非常重要的。

視野狹窄

另一件可以使我們忘記好的評論實踐以及標準的東西是視野狹窄。許多程序員都具有視野狹窄的毛病。你知道這種感覺 - 你解決問題,你處於最佳狀態。你覺得與你的音樂(或沒有)獨立於自己的小世界中,並且你就在編碼,突然兩小時過了,你意識到你已經寫了無數行沒有註釋的代碼。我們所有人偶爾都會遇到這種事情,但重要的是在某處發現這個情況並且補上應有的註釋。

語法和命名的一致性

一致性是一個灰色地帶 – 它更多的是關於編碼標準之類的,但它和防禦性編程也有聯繫。在PHP中,有標準規範你的代碼格式以便別人查看,或者你以後使用。但常常沒人讓你的代碼標準化。但是無論你是否按照標準編碼,你至少要保持一致性 – 這能讓你少犯錯誤。這對於需要大量時間返回並且修復的小的語法錯誤尤其適用。如果你總是使用相同的間隔,格式和語法,命名規格等等你就能更好的避免犯錯以至於誤讀你自己的代碼。你更可能快速瀏覽代碼並且找到你需要的東西。

總結

總的來說,除去用戶行爲和動作,不要對你的程序做任何假設。假設是具有防禦性編程習慣的程序員最大的敵人。不要假設你不需要 default 語句或者 else 代碼塊。儘量使用正確的用戶錯誤信息,警告,日誌或者任何其它你假設不會用到的代碼。你的假設通常是正確的 – 但我們不在乎。我們在乎的是它們出錯的時候。一定要計劃得好,準備着你可能需要在幾小時,幾周,幾個月甚至幾年後回顧你的代碼,或者其他人需要 – 相應的就要好好寫文檔。別假設它永遠不需要升級,擴展或者維護。那是無知的,在更多的情況下是疏忽。有時候保持一顆防禦性編程的心能幫你更有效更安全地估計,計劃和編程。

譯文鏈接:http://www.codeceo.com/article/php-defensive-programming.html
英文原文:Defensive Programming in PHP
翻譯作者:碼農網 – 邱康
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章