۲. ویژگیهای جدید
بعضی این ویژگی صرفا به بهبود روشهای قبلی کمک کرده و بعضی کلا یک روش جدید هست. البته شاید در طول دوران برنامه نویسی حتی یک بار هم به این ویژگیها برخورد نکرده باشید. و این شاید عدم اطلاع از این ویژگیها باشه. بعضی اوقات وقتی به یه ویژگی جدید آشنا میشید، شاید به خودتون بگید عجب این ویژگی بود و من از یه روش دیگه استفاده کردم. مثلا مشکلی رو که شما در ۳۰ خط تونستید حل کنید در php شاید در حد صدا زدن یه تابع بوده. در php7 پویایی زیادی به کار برده شده. استفاده روشهایی که برنامه نویسی رو لذت بخش و عدم پایبند شدن به قوانین سخت دیگر زبانها. دوستانی که زبانهای دیگر رو تجربه کردن و بعد به php رسیدن، تازه شور و شوقی در درونشون روشن شده و اونم پایبند شدن به قدرت تفکر خودشون. php دست برنامه نویس رو همراه با ذهنش باز میذاره. که برنامه نویس فکر کنه چیمیخواد و بعد برای هر کاری تابع و روش داره. در این چند سال تونسته مرحله به مرحله و بروز رسانی مداوم تمام نیازهای برنامهنویس وب رو تامین کنه و در php7 یک پیشرفت بزرگ رو تقدیم برنامهنویسان وب کنه. شاید هنوز هم phpدر مرحله نباشه که بگیم میشه باهاش هر کاری کرد، ولی این طور که داره پیش میره اون روز دور از ذهن نیست. مثلا روی سایت php.net موقع دانلود مشخص کنی php رو برای چه کاری میخوای؟ شاخه وب، شاخه دسکتاپ، شاخه پردازش زبان، شاخه ریاضیات و ...
زمانی پایتون گرد و خاکی به پا کرد و با روبی شاخ به شاخ شد. همون زمانهایی بود که تمام سایتها در ذهن عموم مرگ php رو تحلیل میکردن. ولی آمارها چیز دیگری رو نشون داد. به شخصه تجربه کوچکی رو در پایتون داشتم. ولی چیزی درش ندیدم که بگم الان دیگه پایتون. بعد زمانی که روبی در اوج خودش بود، برنامهنویسانی که در پایتون ماژولهای خوبی ارائه داده بودن در همون سالهای ۲۰۱۰ و ۲۰۱۱ آخرین آپدیتشون بود و مهاجرت به سمت روبی بود. این فراز و فرودها در هر زبانی هست. ولی در مورد php وضع فرق میکنه، همیشه فراز بوده و هست. و اکنون php7 و ویژگیهایش.
نوع داده اسکالار
php به نوع داده آرگومان حساس نیست. ولی شما میتونید این قابلیت رو بهش بدید. مثلا آرگومانها نوعش فقط int باشه و اگر رشته ارسال شد خطا بده. قابلیت خوبی بود در شرایط مورد نیاز ولی ارسال نوع داده سریالی بصورت int ...$rgs هنوز وجود نداشت. با این قابلیت شما میتونید مجموعه داده نوع int رو برای تابع ارسال کنید. البته نوع داده int یه مثال بود و نوعهای بیشتری مثل string,float,bool و معرفی نوعهای جدید در php5 مثل class name, array, interface و callable هم وجود دارن. درکد زیر مثالی از نوع داده اسکالار رو میبینید.
php7-scalar-type.png
تعیین نوع خروجی تابع
php به نوع دادع برگشت از تابع حساس نیست. ولی با php7 شما میتونید مثل مشخص کردن نوع آرگومان تابع، براش نوع خروجی تابع تعیین کنید. البته این قابلیت بسیار شبیه زبانهایی مثل c و cpp هست. که تابعی اگر قرار باشه کارش رو درست انجام بده معمولا نوع int بالای صفر برمیگردونه و اگر منفی برگرده یعنی خطایی بوجود اومده و عدم ادامه برنامه. الان در php7 هم این قابلیت میتونه کمک خوبی باشه. مثلا وب سرویس اگر تونسته کانکت بشه و داده رو ارسال کنه نوع صحیح تعداد دیتای ارسال شده باشه و اگر نتونسته ارسال کنه ۱- برگردونه. در زیر نمونه مثالی از تعریف نوع داده برگشتی رو میبینید. این کد در واقع گرفتن داده json از یک api و ذخیره اون در فایل هست. اگر اتصال گرفتن داده موفقیت آمیز بود، اون وقت داده رو به کمک file_put_contents ذخیره میکنه. این تابع تعداد بایتهای نوشته شده بر روی فایل رو برمیگردونه. اگر عملیات نوشتن هم موفقیت آمیز نبود مقدار false رو برمیگردونه. در کل اگر برنامه ما به catch برسه باز هم یه مقدار منفی رو برمیگردونه که نشان دهنده خروجی ناموفق هست.
کدهای این بخش
function connect_to_web(string $url):int {
try {
$data = file_get_contents($url);
if($data)
return file_put_contents('data/dret_'.time().'.json', "$data\n");
} catch (Exception $e) {
return -1;
}
}
$get_user_info = connect_to_web('http://ipinfo.io/json');
if($get_user_info < 0 ) {
echo "failed get data from the web !!!";
exit(-1);
}
echo "get data from the web, $get_user_info\n";
حاصل اجرای کدها
php7-return-type.png
یکی شدن چک کردن null
همه ما چک کردن وجود null در یک خط رو معمولا استفاده میکنم. که اگر داده وجود داشت اون وقت دستور بعد از ? و اگر وجود نداشت بعد از : اجرا بشه. تابع isset بررسی عدم null بودن رو چک میکنه و نمونه کد زیر
$data = isset($_GET['data'])?$_GET['data']:'nobody';
حالا در php7 این دستور کمی مهربانتر و کوچکتر و حتی کاربردیتر هم شده. بجای کد بالا از کد زیر میتونید استفاده کنید
$data = $_GET['data'] ?? 'nobody';
و حتی قویتر از اون که اگر داده GET موجود بود از get استفاده کن و اگر داده POST موجود بود از post و در آخر اگر نبود nobody قرار بده
$data= $_GET['data'] ?? $_POST['data'] ?? 'nobody';
مقایسه شرطی دو متغیر
نیاز هست که بسنجیم آیا مقدار اول از دوم بزرگتر هست، مساوی هست یا کوچکتر. با switch یا چند تا if میشه این کار رو کرد. ولی این بار php7 دستور شرطی جدیدی رو تقدیم کرده. اگر مساوی باشن مقدار 0 و اگر مقدار اول از دوم بزرگتر باشه 1 و اگر مقدار اول از دوم کوچکتر باشه مقدار 1- رو برمیگردونه. تکه کد زیر
echo "a" <=> "a"; // 0
echo "a" <=> "b"; // -1
echo "b" <=> "a"; // 1
تعریف ثابت آرایهای
منو یاد کدهای c انداخت. در برنامههای c معمولا یه مجموعهای رو برای تعریف خطا استفاده میکنن. یه نوع enum بالا تعریف میکنم . و در زیر آرایهای متناظر با اون enum. توی کل برنامه خطایی رو میخوام برگردونم اون ثابت enum رو پاس میدم. که با داشتن آرایه متناظر میتونید رشته خطا رو بدست بیارید. یه جور آرایه ثابت برای نگه داشتن متن خطاها هست. حالا در php7 این کار انجام شده. یعنی شما میتویند یه آرایه ثابت تعریف کنید. این خیلی کاربردی هست. بعضی کارها مثل همین خطاها برای debug برنامه میشه گذاشت و توی کل برنامه از اون خطاها استفاده کرد.
برای نمونه این کد رو که برای تبدیل خطاها رو در نظر بگیرید
<?php
define('SUCCESS',0);
define('FILE_NOT_FOUND',1);
define('DATABASE_NOT_EXISTS',2);
define('ERR',[
FILE_NOT_FOUND=>'config file not found, run install.php',
DATABASE_NOT_EXISTS=>'database not eists. create new database.'
]);
function connect_to_db( $config_file ):int {
if(!file_exists($config_file))
return FILE_NOT_FOUND;
return SUCCESS;
}
$is_connect = connect_to_db('/etc/php7test.ini');
if($is_connect != SUCCESS)
echo ERR[$is_connect];
در ابتدا حالت موفقیت آمیز بودن با 0 تعیین شده، و بعد اعداد بزرگتر از صفر حالتهای خطا هستن. متغییر آرایهای ERR تمام رشته خطاها رو نگه میداره. با برخورد با هر خطایی در طول برنامه، تابع شما ثابت خطایی رو ارسال میکنه. شما در برنامه میسنجید که اگر برابر با SUCCESS نباشه پس خطا هست و رشته متناظر با خطا رو به کمک ERR نمایش میدید. همچنین تمام توابع این چنین که مثلا باید متصل بشه یا مقداری رو چک کنه، میتونید نوع int بگیرید که بسته به شرایط عدد متناظری برگشت داده میشه.
کلاس بینام
کلاسها در php با شروع تعریف یک کلاس آغاز میشه. ولی در php7 امکان تعریف کلاس بینام یه بقول خودمون کلاسهای یهویی هست. مثلا در جایی از برنامه برای ارسال داده نیاز به کلاسی دارید. لازم نیست برگردید و کلاس تعریف کنید، بلکه در همین خط کافی هست یه کلاس جدید بسازید و پاس بدید به تابع. اون تابع هم فهمی از این که کلاس واقعا تعریف شده یا بینام ساختید رو نداره. صرفا کاری که شما میخواید رو براتون انجام میده. حالا بر روی کد بیشتر با هم بررسی میکنیم:
<?php
interface Name{
public function name(string $name);
}
class AppName {
private $name;
public function setName(Name $name) {
$this->name= $name;
}
public function getName():Name {
return $this->name;
}
}
$appname = new AppName;
$appname->setName(new class implements Name{
public function name(string $name) {
echo "$name";
}
});
echo $appname->getName()->name('mehrdad');
در ابتدا یه اینترفیس بنام Name تعریف شده که تابع name در اون همراه با یدونه آرگومان string قرار داده. یه جور definition کلاس هست.
و بعد کلاس AppName با کارهای زیر تعریف شده
۱. متغیر private بنام name برای نگهداری وضعیت وو مقدار یک کلاس
۲. senName که مقداری به نوع Name میگیره و در متغیر خصوصی name ذخیره میشکنه
۳. getName که مقدار خصوصی name رو برگشت میده
حالا در استفاده از کلاس AppName موقع call کردن متد setName یه کلاس جدید در همون ارسال آرگومان تعریف شده. این کلاس یه تابع name داره که نام رو بر روی صفحه چاپ میکنه. این کلاس بر روی کلاس AppName و متغیر خصوصی name ذخیره میشه و در خط بعد با صدا زدن getName مقدار برگشت داده میشه. از اون جایی که در تعریف کلاس بینام نوشتیم که مقدار ورودی رو echo کنه، بهش یه مقدار string میدیم. و اونم روی صفحه چاپ میکنه.
این نمونه کد چندان کاربردی نبود. ولی در جاهایی که نیاز به تغییر جایی از برنامه هست خیلی کاربردی هست. مثلا در طراحی ui شما میتونید کل کدهای css رو بصورت کلاس بندی شده و id درون فایل ذخیره کنید و به هر المنتی کلاس و id خودش رو بدید. ولی این به معنی نیست که دیگه نمیشه استایل یه المنت رو تغییر داد. بلکه با صدا زدن style در هر المنتی میتونید درش تغییرات ایجاد کنید. الان در php7 هم همینطور شده، دست شما بازه که هر کجا خواستید بسته به نیاز برنامه، مسیر رو تغییر بدید یا یه چیز دیگه از توش دربیارید. همین interface رو میتویند در یه فایل ذخیره کنید و در فایلهای دیگه فراخوانی کنید و در اون فایلهای استفاده دیگری ازش کنید. مثلا در فایلی فقط name رو چاپ کنه ولی در یه فایل دیگه name رو روی سوکت ارسال کنه به شبکه.
جای دادن یونیکد درون رشته
یادمه این مشکل برای یکی از کاربران پیش اومده بود. که مقدار یونیکد هگزادسیمال درون رشته از بین میرفت. در php7 برای قراردادن مقدار هگزادسیمال یه یونیکد از گذاشتن u\ و مقدار هگزادسیمال درون آکولاد همراه با دابل کوتیشن. البته بصورت اختیاری درون آکولاد میتونه با 0 یا هر تعداد بیشتر 0 شروع بشه.
تصویر زیر نمونه کد و اجرای اون رو نشون میده
php7-escape-unicode.png
بستار و انقیاد
میدونم شما هم مثل من مفهوم جمله بالا رو نفهمدید. منم درکش برام سخته. ولی باور کنید خواستم فارسی رو پاس بدارم. نمیشه. آخه مفهوم bind کردن رو چطور میشه انقیاد یا الزام ترجمه کرد. مفهوم bind رو فقط باید گفت bind. مثلا در برنامه نویسی شبکه سوکت رو روی یه پورتی bind میکنید. بستار هم همون closure هست. درست کردن تابعی که کاری رو بسته به کلاسی انجام میده. مثلا شما کلاسی دارید که متغیر x در اون تعریف شده. میتونید یه تابع closure بسازید و bind کنید روی اون کلاس. این تابع closure از متغیر x کلاس استفاده میکنه و کاری رو که ازش انتظار دارید براتون انجام میده. کد زیر این موضوع رو بهتر نشون میده
<?php
/**
* base closure class
*/
class Name
{
/**
* sample 1 for return name
*/
private $name = 'PHP-7';
/**
* sample 2 for get argument and return string on the method
*/
public function add( $extra ) {
return "$extra {$this->name}";
}
}
echo "<br/> --------- sample 1 call --------- <br/>";
$get_name = function() {
return $this->name;
};
echo $get_name->call(new Name);
echo "<br/> --------- sample 2 call --------- <br/>";
$add_name = function() {
return $this->add('programming');
};
echo $add_name->call(new Name);
مقدارهای closure از php5 هم بوده ولی روش فراخوانی و استفاده از اون در php7 بهتر شده. همچنین اگر همین closure نمونه کد php5 رو براتون بزارم به اشتباه خواهید و رفت و درکش یکم براتون سخت میشه.
در کد بالا یه کلاس Name تعریف شده که متغیر خصوصی name داره و متد add
در پایین اومدیم و با روش closure یه تابع تعریف کردیم و بعد با call اون رو bind کردیم روی کلاس Name. تابع closure ما میومد و مقدار name رو میگرفت و چاپ میکرد. به محض صدا زدن call این تابع جزوی از متدهای کلاس Name میشه و مقدار name رو بر روی صفحه چاپ میکنه
در closure دست شما بازه و هر کاری میتونید کنید مثلا مقدار بگیرید یا مقدار بفرستید و کارهای معمول دیگه. مثال دوم مقدار programming رو برای تابع add ارسال کرده و مقدار رو return میکنه.
خروجی کد بالا
php7-closure-bind.png
امنیت بیشتر در unserialize
این یه حفره برای ورود به نرمافزارها بود. اگر میتونستید به دیتابیس یه برنامه ورود کنید و از قضا طرف وضعیت کلاسها رو برای پردازش بعدی درون دیتابیس نگهداری کنه، خیلی راحت کافی بود کدهای خودتون رو تذریق کنید و سایت رو پایین بیارید.
در serialize شما میتونید وضعیت فعلی یک کلاس یا object رو بصورت string در بیارید و هر موقع نیاز بود اون رو با unserialize برگردونید. در php7 یه امکان امنیتی بصورت آرگومان دوم بهش اضافه شده که توانایی تذریق کد رو میگیره. آرگومان دوم بصورت آرایه بهش پاس داده میشه و اونم allowed_classes هست. درش یه سری کلاسهای معتبر رو وارد میکنید و در موقع unserialize کدهای خارج از اون کلاس رو بررسی نمیکنه.
کد زیر همراه با تصویر اجرای برنامه امنیت unserialize رو نشون میده
<?php
class Name
{
private $name;
public function setName( $name ) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
$name = new Name;
$name->setName('programming PHP-7');
$save = serialize($name);
echo "serialized name object: $save <br/><br/>";
$ret_saved = unserialize($save,['allowed_classes'=>['Name']]);
echo "unserialized: ". $ret_saved->getName();
php7-unserialize.png
کلاس IntlChar
کلاس جامع intl خیلی کاربردی هست. مثلا تقویم فارسی داره یا خیلی کارهای دیگه میشه باهاض انجام داد. این بار برای بازی با کاراکترها مجموعه توابعی رو تحت کلاس IntlChar در php7 ارائه شده. مثلا میتونید سنجش بزرگ یا کوچک بودن. یا بجای کاراکتر @ حرف COMMERCIAL AT گذاشته بشه. کل متدهای این کلاس در این آدرس هست
×××××××××× بخش ویژگیهای جدید همچنان ادامه داره و در روزهای بعدی به همین پست اضافه خواهد شد×××××