شیوه‌هایی بهتر در PHP

شیوه‌هایی بهتر در PHP
شیوه‌هایی بهتر در PHP


در هر زبان برنامه‌نویسی‌ای مفهومی به نام Best Practice یا همان روش ایده‌آل وجود دارد، که معمولا این روش از بین چند روشی که برای انجام یک کار میتوان به‌کار بست انتخاب می‌شود.

اینکه چرا باید از Best Practice ها استفاده نمود، دلایل مختلفی از جمله مسائل امنیتی، عملکردی (Performance) و ... می‌تواند داشته باشد.

۱. ذخیره کلمات عبور
از جمله روش‌هایی که برای ذخیره کلمات عبور استفاده می‌شود، استفاده از الگوریتم‌های MD5 و SHA1 است که این روش‌ها امنیت کافی برای ذخیره کلمات عبور را ندارند.

برای ذخیره کلمات عبور از فانکشن password_hash استفاده کنید، چراکه از جدیدترین و بهترین مدتهای هَش سازی استفاده می‌کند.
<?php
    // Hash the password.  $hashedPassword will be a 60-character string.
    $hashedPassword = password_hash('mypassword', PASSWORD_DEFAULT);
 
    password_verify('the wrong password', $hashedPassword); // false
    password_verify('mypassword', $hashedPassword); // true
?>


۲. اتصال به دیتابیس
برای اتصال به دیتابیس از درایور PDO استفاده کنید. این درایور به دیتابیس‌های مختلفی می‌تواند متصل شود و به صورت OOP قابل استفاده است.
در PDO می‌توانید از فانکشن‌های Prepend برای جلوگیری از حملات SQL Injection استفاده نمایید.

<?php
try {
    $link = new \PDO('mysql:host=your-hostname;dbname=your-db;charset=utf8mb4',
    'your-username',
    'your-password',
        array(
            \PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
            \PDO::ATTR_PERSISTENT => false
        )
    );

    $handle = $link->prepare('select Username from Users where UserId = ? or Username = ? limit ?');
    
    $handle->bindValue(1, 100, PDO::PARAM_INT);
    $handle->bindValue(2, 'Bilbo Baggins');
    $handle->bindValue(3, 5, PDO::PARAM_INT);
    $handle->execute();
    
    $result = $handle->fetchAll(\PDO::FETCH_OBJ);
    foreach($result as $row) {
        print($row->Username);
    }
} catch(\PDOException $ex) {
    print($ex->getMessage());
}
?>


۳. تگ شروع و پایان PHP
از تگ‌های <? ?> و یا <? =?> استفاده نکنید و بجای آن از شکل کامل <? php?> استفاده کنید. با اینکه شکل کوتاه راحت‌تر به نظر می‌رسد ولی بطور پیش‌فرض در تنظیمات PHP غیرفعال است و برای استفاده از آنها پارامتر short_open_tag باید فعال شود. همینطور ممکن است در سروری که از آن استفاده می‌کنید امکان فعال‌سازی این پارامتر وجود نداشته باشد.

حالت =?> بدون نیاز به فعال بودن short_open_tag کار می‌کند و برای استفاده از آن مشکلی وجود ندارد.


۴. استفاده از autoload
روش قدیمی autoload کردن کلاس‌هایی که لود نشده‌اند استفاده از فانکشن

function __autoload() {}

می‌باشد. مشکل در استفاده از این فانکشن آنجاست که اگر کتابخانه‌ای را وارد پروژه کنید که از این فانکشن استفاده می‌‌کند؛ در این صورت با تداخل (conflict) مواجه خواهید شد.
روش مناسب و صحیح در autoload کردن، تعیین نامی منحصربه‌فرد برای فانکشنی که کار autoload را در کد شما انجام می‌دهد و سپس ثبت آن در

spl_autoload_register()

است.

<?php
// First, define your auto-load function.
function MyAutoload($className) {
    include_once($className . '.php');
}

// Next, register it with PHP.
spl_autoload_register('MyAutoload');

// Try it out!
// Since we haven't included a file defining the MyClass object, our auto-loader will kick in and include MyClass.php.

// For this example, assume the MyClass class is defined in the MyClass.php file.
$var = new MyClass();
?>


۵. سینگِل‌کوتِیشِن در مقابل دابِل‌کوتِیشِن
در PHP سینگِل‌کوتِیشِن‌ها ( ' ) تجزیه (parse) نمی‌شوند، به این معنی که هر کاراکتری که بین آنها قرار دهید مستقیما چاپ می‌شود. در مقابل دابِل‌کوتِیشِن‌ها ( " ) تجزیه می‌شوند و این امکان را دارند تا متغیر بین آنها قرار گیرد. همینطور کاراکترهایی مانند n\ یا t\ در دابِل‌کوتِیشِن‌ها قابلیت اجرایی دارند.
دابِل‌کوتِیشِن‌ها در لحظه‌ی اجرای برنامه ارزیابی (evaluate) می‌شوند، در حالیکه سینگِل‌کوتِیشِن‌ها اینچنین نیستند و به همین دلیل سینگِل‌کوتِیشِن‌ها از نظر عملکرد بهتر هستند. معمولا این تفاوت در عملکرد، در نرم‌افزارهای بسیار بزرگ قابل لمس است و در اکثر پروژه‌ها تفاوتی بین آنها احساس نمی‌شود.

۶. استفاده از const در مقابل فانکشن define
تفاوت‌های const و define :
۱. ()define در زمان run time تعریف می‌شود درحالیکه const در زمان compile time. به همین دلیل const با کمی performance بهتر همراه است (که این موضوع در نرم افزارهای معمول به چشم نمی‌خورد).
۲. از ()define برای تعریف ثوابت در کلاس‌ها نمی‌توان استفاده کرد، همینطور ()define ثابت را در بلاکِ GLOBAL قرار می‌دهد.
۳. امکان استفاده از عملگرهای بیتی در ()define وجود دارد.
۴. از ()define در بلاک‌هایی مانند if می‌توان استفاده نمود درحالیکه از const نمی‌توان.

 <?php 
 // Let's see how the two methods treat namespaces
 namespace MiddleEarth\Creatures\Dwarves; 
 const GIMLI_ID = 1; 
 define('MiddleEarth\Creatures\Elves\LEGOLAS_ID', 2); 

echo(\MiddleEarth\Creatures\Dwarves\GIMLI_ID);  // 1
echo(\MiddleEarth\Creatures\Elves\LEGOLAS_ID);  // 2; note that we used define(), but the namespace is still recognized 
 
// Now let's declare some bit-shifted constants representing ways to enter Mordor. 
define('TRANSPORT_METHOD_SNEAKING', 1 << 0); // OK! 
const TRANSPORT_METHOD_WALKING = 1 << 1; // Compile error! const can't use expressions as values 

// Next, conditional constants. define('HOBBITS_FRODO_ID', 1); 
if($isGoingToMordor) { 
    define('TRANSPORT_METHOD', TRANSPORT_METHOD_SNEAKING); // OK!    
    const PARTY_LEADER_ID = HOBBITS_FRODO_ID // Compile error: const can't be used in an if block 
} 
    
// Finally, class constants 
class OneRing { 
    const MELTING_POINT_CELSIUS = 1000000; // OK!
    define('MELTING_POINT_ELVISH_DEGREES', 200); // Compile error: can't use define() within a class 
} 
?> 

عملا استفاده از ()define انعطاف بیشتری در برنامه‌نویسی به شما می‌دهد مگر اینکه بخواهید در کلاس‌های خود از ثابت استفاده کنید که در این صورت باید از const استفاده کنید. همینطور const خوانایی بیشتری به کدهای شما می‌دهد.

۷. عبارات با قاعده در PHP
در PHP دو روش برای کار با عبارات با قاعده (Regex) وجود دارد. PERL که فانکشن‌های آن با *_preg شروع می‌شوند و POSIX که فانکشن‌های آن با *_ereg شروع می‌شوند.
POSIX از نسخه 5.3 PHP منسوخ شد و به همین دلیل باید از خانواده *_preg استفاده نمایید.


۸. ارسال ایمیل در PHP
فانکشن ()mail از فانکشن‌های موجود در هسته‌ی PHP است که استفاده از آن مشکلات امنیتی دارد. به همین دلیل برای ارسال ایمیل باید از کتابخانه PHPMailer استفاده نمود. این کتابخانه‌ی متن‌باز بسیار محبوب بوده و در استفاده از آن نیازی به نگرانی در مورد مسائل امنیتی نیست.

<?php
// Include the PHPMailer library
require_once('phpmailer-5.2.7/PHPMailerAutoload.php');

// Passing 'true' enables exceptions.  This is optional and defaults to false.
$mailer = new PHPMailer(true);

// Send a mail from Bilbo Baggins to Gandalf the Grey
// Set up to, from, and the message body.  The body doesn't have to be HTML; check the PHPMailer documentation for details.

$mailer->Sender = 'bbaggins@example.com';
$mailer->AddReplyTo('bbaggins@example.com', 'Bilbo Baggins');
$mailer->SetFrom('bbaggins@example.com', 'Bilbo Baggins');
$mailer->AddAddress('gandalf@example.com');
$mailer->Subject = 'The finest weed in the South Farthing';
$mailer->MsgHTML('<p>You really must try it, Gandalf!</p><p>-Bilbo</p>');

// Set up our connection information.
$mailer->IsSMTP();
$mailer->SMTPAuth = true;
$mailer->SMTPSecure = 'ssl';
$mailer->Port = 465;
$mailer->Host = 'my smtp host';
$mailer->Username = 'my smtp username';
$mailer->Password = 'my smtp password';

// All done!
$mailer->Send();
?>


۹. اعتبارسنجی آدرس ایمیل
اغلب برنامه‌نویسان PHP از Regex هایی پیچیده برای بررسی اعتبار فرمت ایمیل‌ها استفاده می‌کنند. اما برای این اعتبارسنجی راه بسیار راحت‌تری وجود دارد.

<?php
filter_var('sgamgee@example.com', FILTER_VALIDATE_EMAIL); // Returns "sgamgee@example.com". This is a valid email address.
filter_var('sauron@mordor', FILTER_VALIDATE_EMAIL); // Returns boolean false! This is *not* a valid email address.
?>


منبع : phpbestpractices