• 0 رای - 0 میانگین
  • 1
  • 2
  • 3
  • 4
  • 5
رفتار دردسرساز switch
#1
تست:
کد پی‌اچ‌پی:
<?php

$v
=0;

switch(
$v) {

case 
'hello':
    echo 
'hello';
break;
case 
'goodbye':
    echo 
'goodbye';
break;
default:
    echo 
'default';
break;

}

?>
خروجی: hello

این رفتار غیرمنتظره switch دیشب در برنامم یه باگ ایجاد کرده بود که قدم به قدم تست کردم تا رسیدم به switch و فهمیدم جریان چیه!

من switch رو به این شکل تغییر دادم تا دیگه نظیر چنین مواردی رخ ندن:
کد پی‌اچ‌پی:
<?php

$v
=0;

switch(
"$v") {

case 
'hello':
    echo 
'hello';
break;
case 
'goodbye':
    echo 
'goodbye';
break;
default:
    echo 
'default';
break;

}

?>

من نمیخواستم از === استفاده کنم، چون گاهی ممکن بود یک رشته بهش بدم و گاهی هم مثل همین مثال یک عدد باشه. یعنی اینطوری انعطاف بیشتری داره.

نقل قول:این if و else هم همین مشکل رو دارن!
راست میگی عجیبه ها!
کد پی‌اچ‌پی:
var_dump('hello'==0); 
true میده!

بنظر میرسه دوباره PHP گند زده Big Grin
من تنها چیزی به این عجیبی و بدی که یادم هست ویژگی «رجیستر گلوبالز» بود.
اون زمان وقتی این ویژگی احمقانه رو دیدم و با دردسرهای امنیتی بزرگی که ایجاد میکرد مواجه شدم، مطمئن شدم که طراحانش یجورایی ناشی بودن!
الانم ظاهرا همون داستان داره به شکل دیگری تکرار میشه.
آخه چه وضعشه، انعطاف و زبان سطح بالا و دینامیک تایپ درست، ولی دیگه نه در این حد چیزهای عجیب و غیرمنتظره که میتونن براحتی باگ و مسائل امنیتی پنهان ایجاد کنن!

آدم به زبان برنامه نویسی هم نتونه اعتماد کنه دیگه سنگ روی سنگ بند نمیشه!!
  پاسخ
تشکر شده توسط : Muhammad-Ali masoudmanson
#2
نقل قول:این مسئله چیز خاصی نیست و PHP هم به قول شما گند نزده! مسئله اینه که ازنظر عملگر == رشته 'hello' و عدد 0 با هم برابر هستن. چرا؟ چون موقع تبدیل نوع رشته هایی که با عدد شروع نشه، مساوی صفر درنظر گرفته میشه ولی اگه با عدد شروع بشه، تا جایی که بتونه رو جدا میکنه و بقیه رو حذف میکنه. مثلاً '25hello' برابر با عدد 25 میشه. توی سایتش هم اشاره کرده (لینک) :
مهندس اینا که گفتی همه توجیه بودن و یجورایی انگار طرز پیاده سازیش رو گفتید یا اینکه انگار یه محدودیت فنی در این زمینه وجود داره.
ما در سطح منطقی و انتظار برنامه نویس و امنیت برنامه باید بهش نگاه کنیم، و این زبان برنامه نویسی است که باید خودش رو با این انتظار تطبیق بده. شاید بخصوص که یک زبان برنامه نویسی سطح بالا باشه!

شما در کدام زبان دیگری چنین چیز عجیبی میبینید؟
چرا واسه اونا محدودیتی نبوده؟
چرا اونا رو به این شکل طراحی نکردن؟

مثلا در جاوااسکریپت، که همین الان با تست دارم بهتون میگم، و اونم یک زبان داینامیک تایپ و سطح بالا و مربوط به وب است و با داده های مشابهی سروکار داره:
کد:
<script>
document.write('0'==0);
</script>
خروجی: true
اما این:
کد:
<script>
document.write('hello'==0);
</script>
خروجی: false

جاوااسکریپت از این نظر و از نظر کاربرد به PHP خیلی شبیه است. اون عملگر === رو هم داره. ولی در همچین موردی چنین کاری نکرده و البته کسی هم انتظار نداره! همین غیرمنتظره بودن و عدم درک منطق از سوی برنامه نویس هست که درست نیست. اگر منطقی داره، باید برنامه نویس هم بفهمه و انتظار داشته باشه. ما از منطق و انتظار منطقی صحبت میکنیم، نه محدودیت های فنی و نحوهء پیاده سازی. درواقع هیچ محدودیت فنی و مشکل پیاده سازی در این مورد وجود نداره و میتونستن از منطقی مشابه بقیهء زبانهای دینامیک و سطح بالا و وبی پیروی کنن. اینطوری از این نظر که بین زبانها سازگاری وجود داشت هم خوب بود، و از این نظر که برنامه نویس گیج نشه و خطا نکنه هم خوب بود. یعنی حتی اگر منطقی برای این رفتار بنظرشون میرسید (که تاحالا ندیدم)، بازهم ممکن بود وزن این سازگاری و هماهنگی یادگیری و کار، بر اون منطق و فایده بچربه.

هیچ زبانی اندازهء PHP اینقدر بی بند و بار نیست

دیدید که جاوااسکریپت در این مورد اینطور فکر و عمل نمیکنه.
و البته فکر نمیکنم هیچ زبانی جز PHP هم چنین کاری کرده باشه. شاید حتی در کل تاریخ برنامه نویسی چنین موردی نبوده!!

راستی الان با پایتون هم اومدم تست کنم.
پایتون هم داینامیک تایپ هست، اما حتی 0=='0' رو هم به رسمیت نمیشناسه!
کد:
print(0=='0')
خروجی: False

البته من شخصا PHP رو خیلی دوست دارم.
بقول یارو، این حرفا چیزی از ارزشهاش کم نمیکنه Big Grin
آلترناتیو مناسبی سراغ ندارم که بتونه جای PHP رو بگیره.
یک زبان بازمتن، مجانی، با این همه انعطاف و راحتی و امکانات.
میگن دندون اسب پیشکشی رو که نمیشمارن!
درکل چیز خوبیه.
ولی این موارد رو باید قبول کرد که اشتباهات طراحی هستن.
یا حداقل باید نسبت بهشون خیلی مشکوک بود.
هرچیزی باید منطقی داشته باشه.
و باید تمامی جوانبش رو درنظر گرفت.

اگر این موارد رو توش اصلاح کنن خب زبان بهتری میشه!
ولی اینکه نه یک بار، بلکه چند بار نظیر چنین تصمیماتی در طراحی گرفته و اجرا میشن، آدم رو به یه فکرهایی و وحشت میندازه Big Grin
  پاسخ
تشکر شده توسط : masoudmanson
#3
موضوع اینه که از نظر برنامه نویس وقتی اینطور مقایسه ها رو داریم انجام میدیم بطور معمول دنبال مقایسه بر اساس ارزش عددی اونا نیستیم.

ارزش عددی یک رشته، یعنی تبدیلش به عدد، توابع صریح خودش رو داره و بعضی وقتا که نیاز داریم انجام میدیم.
ولی اینکه PHP این رفتار و موارد معدود رو به کل مقایسه ها تعمیم بده، جالب نیست! چون در عمل احتمالش خیلی کمه که منظور ما از اون مقایسه همونی بوده باشه که PHP داره بر اساسش عمل میکنه، و احتمال اینطور مقایسه مفید باشه و به نتیجهء منطقی درستی در برنامه منجر بشه خیلی کمه.

اینکه یه عدد توی یه رشته باشه اگر کاراکترهای عددی به تنهایی باشن خب یه چیزی، ولی وقتی کاراکترهای دیگری هم هستن، یا در مثال ما اصلا هیچ کاراکتر رقم توی رشته نیست، خیلی احتمالش کمه که منظور مقایسهء بر اساس ارزش عددی بوده باشه.
در اینطور موارد باید مقایسهء رشته ای باید صورت بگیره و اون عدد به رشته تبدیل بشه و با رشتهء دیگر مقایسه بشه، نه اینکه رشته به عدد تبدیل بشه!

واقعا در منطق و الگوریتم برنامهء شما چقدر احتمال مقایسهء معنا دار چنین مواردی میره؟!
منظورم اینه که یک رشته رو بخواید بر اساس ارزش عددیش با عدد مقایسه کنید. البته در موارد عادی ما این کار رو زیاد انجام میدیم، اما در اینطور موارد خود اون رشته هم محتوی یک عدده. خیلی کم پیش میاد که کاراکترهای غیررقمی هم درش باشن و منظور ما مقایسه بر اساس ارزش عددی باشه، و بازهم کمتر از این پیش میاد که اصلا هیچ کاراکتر رقمی توش نباشه و منظور ما مقایسه بر اساس ارزش عددی بوده باشه.
منکه چیزی به ذهنم نمیرسه.
طبیعتا احتمالش کمه و احتمال بیشتر مقایسهء رشته ایه.
بقیهء زبانهای داینامیک هم از همین پیروی میکنن.
بعضیا حتی سختگیرتر هم هستن.
خود داینامیک تایپ بودن توسط بعضیا مورد انتقاده و از دید و جنبه هایی یجورایی بی بند و باری و مایهء ایجاد باگ و برنامه نویسی بی دقت تلقی میشه، بعد PHP اومده رفتار سلیقه ای و غیرمنتظره رو به حد اعلی رسونده؛ بخاطر همین میگم که خیلی بی بند و باره Big Grin
البته من اعتقادی ندارم که داینامیک تایپ بودن خوب نیست، بلکه بنظر من حداقل در حیطهء زبانها و کاربردهای خاص خودش خیلی هم چیز خوبیه، ولی PHP دیگه دنده خلاص رو زده رفته یجایی که اصلا معلوم نیست کجاست و چرا!
  پاسخ
تشکر شده توسط : masoudmanson
#4
http://www.php.net/manual/en/language.ty...ggling.php

http://www.php.net/manual/en/types.comparisons.php
  پاسخ
تشکر شده توسط :
#5
بابا لینک و اینا الکی ننداز!
در فروم برنامه نویس قبلا تمام اینا رو دیدم و بحثش شده.
ما هم نگفتیم این مثلا باگه و از زیردستشون در رفته باشه. واسه خودشون توجیهی دارن و این تصمیم طراحی ای بوده که گرفتن.
ولی مسئله اینه که توجیه منطقی و فایدش در برنامه نویسی هم آیا توجیه میشه یا نه. که بنظر بنده نمیشه و این یک طراحی غلط بوده!
علتش رو هم تاحالا توضیح دادم دقت کنید.
همینطور با زبانهای دیگر مشابه مقایسه کنید.
گیر هم بیشتر سر موارد غیرعادی ای مثل ‎‎'hello'==0 هست که در PHP درست فرض میشه ولی در زبانهای دیگر اینطور نیست.
  پاسخ
تشکر شده توسط : masoudmanson
#6
خب همونطور که خودت گفتی این به خاطر طرحی بوده که توی برنامه نویسی میشده. البته نگرشی که php داشته این بوده که بیشتر متغیر ها از سمت کاربر مقدار دهی میشه و چون همیشه باید از طریق type cast مقادیر رو به type های خودش تعریف کرد می تونه خطاهای غیر قابل پیش بینی رو به وجود بیاره. حتی توی php تبدیل آرایه به رشته با یک وارنینگ انجام میشه و منجر به fetal error نمیشه. اگر این رفتار رو نداشت در خیلی از جاهای دیگه این اخطار رو نشون میداد.
ولی در کل رفتار از پیش تعریف شده بر اساس نیاز برنامه نویسی بود که قرار بوده ساده باشه و به همین خاطر این تبدیل نوع خودکار انجام میشه.
  پاسخ
تشکر شده توسط : masoudmanson
#7
(۱۳۹۲ دى ۰۵, ۱۰:۴۰ ق.ظ)admin نوشته: ولی در کل رفتار از پیش تعریف شده بر اساس نیاز برنامه نویسی بود که قرار بوده ساده باشه و به همین خاطر این تبدیل نوع خودکار انجام میشه.
اتفاقا بعکس، یادگیری و برنامه نویسی رو با چیزهای غیرمنتظره ای مثل ‎‎'hello'==0 دشوارتر و مستعد باگ کرده.
دقت کن که حرف من روی اینطور موارد خاص هست، وگرنه با کل مسئلهء داینامیک تایپ بودن و implicit type conversion مخالف نیستم و حرفت از نظر کلی درسته.
در زبانهای دیگری هم حتی در سطح و حیطهء کاربرد PHP، ما این داینامیک تایپ بودن و implicit type conversion رو داریم و همینطور تبدیل ها موقع مقایسه و غیره انجام میشن، ولی در هیچکدام ‎‎'hello'==0 نمیشه!
PHP میتونست بدون اینکه چنین موارد غیرمنتظره ای رو که عملا کاربرد خیلی کمی دارن و بیشتر مستعد ایجاد باگ هستن درست کنه، از اون منطق و فلسفه و مزایایی که گفتی بهره ببره. همانطور که زبانهای دیگر میکنن.

بقیهء بحث و استدلال ها رو هم بهتر در فروم برنامه نویس دنبال کنی، چون بحث بیشتر اونجا صورت گرفته و نمیخوام مدام مجبور باشم یک چیزی رو تکرار کنم یا پستها رو کپی کنم اینجا.

فعلا این لینک دو پست اخیر و مرتبط:

http://barnamenevis.org/showthread.php?4...ost1939245

http://barnamenevis.org/showthread.php?4...ost1939252

درسته ما خیلی چیزها رو از کاربر دریافت میکنیم، ولی تبدیل و تفسیر خودکار هم حدی داره. باید تاحدی باشه که بقدر کافی محتمل، معقول، قابل انتظار، مفید، و امن باشه.
فرض کن مثلا در یک فرمی کاربر در یک فیلد که مقدارش باید یک عدد باشه، اشتباه یک کلمه رشته ای وارد میکنه (مثلا عبارت yes)، بعد PHP در دستورهای شرطی و عملیات ریاضی مقدار اون رشته رو صفر فرض میکنه؟!
بنظر من نباید اینطور باشه.
معلومه که کاربر اشتباه وارد کرده.
PHP در این مورد باید خطا بده، نه اینکه سرخود برداره هرچیزی رو که نمیفهمه به عدد صفر تبدیل کنه!
اینطور چیزها بیشتر از اونکه کاربرد مفید داشته باشن در برنامه نویسی و برنامه نویسی رو راحتتر کنن، باعث ایجاد باگ و دشوارتر شدن برنامه نویسی امن میشن.
  پاسخ
تشکر شده توسط :
#8
من قبول دارم که این موضوع می تونه منجر به باگ باشه ولی خب می تونه جلوی بعضی از باگهای دیگه که با ورودی از سمت کاربر هست رو بگیره. (نمی دونم منظورم رو متوجه میشی یا مثال بیارم) این تفاوت زبان php با زبان های دیگه برای کسایی که با چند زبان کار می کنن وجود داره. قضیه تبدیل نوع در php جز چیزهای پایه‌ایش بوده و همیشه توی منوال هر جا این اتفاق می افته حتما اشاره کرده.
این قضیه توی زبانهای برنامه نویسی دیگه هم هست. مثلا توی javascript
parseInt('hello')
خروجیش
NaN هست و اخطاری نمیده
NaN واقعا بی معنی هست. تایپی که حتی با خودش هم برابر نیست.
  پاسخ
تشکر شده توسط :
#9
البته از دید من با وجود فریم ورکهای موجود که ورودی های کاربر رو فیلتر می کنن نیازی به تبدیل نوع در این سطح نیست.
یک چیز رو باید قبول کنیم php پایه خیلی ضعیفی رو داشت و اصلا برای این مقاصد پیاده سازی نشد. نمی دونم وقتی php رو بر پایه perl نوشتن هم این رفتار رو داشته یا نه. ولی ممکنه این رفتار از اونجا اومده باشه که خب به عنوان یک اسکریپتی که برای سریعتر کار کردن یک شخص و نه برای اینکه در این وسعت و به عنوان زبان برنامه نویسی مطرح در وب باشه نوشته بشه منطقی هست.
php خیلی مشکلات دیگه ای رو هم هنوز داره که احمقانست. مثلا با هر بار اجرا درخواسست همیشه یه چیزی مثل bootstrap توی نرم افزار ما باید اجرا بشه و یه ماشین مجازی براش نداره (به جز HHVM که مربوط به خود php نیست و هنوز در سطح محصولات نهایی قابل استفاده نیست)
  پاسخ
تشکر شده توسط : hamid_80386 vejmad
#10
(۱۳۹۲ دى ۰۵, ۰۸:۴۵ ب.ظ)admin نوشته: توی javascript
parseInt('hello')
خروجیش
NaN هست و اخطاری نمیده
NaN واقعا بی معنی هست. تایپی که حتی با خودش هم برابر نیست.
NaN خودش مثل یک خطا میمونه دیگه.
یک مقدار خاصه.
اتفاقا همینکه حتی با خودش هم برابر نیست بخاطر همینه که یک حالت نامعلوم/خطا تلقی میشه و بنابراین مقایسهء نتیجهء دو محاسبه که منجر به این مقدار شدن با هم، نباید هم true بشه!
پرینت کردن که مهم نیست و خطری نداره! ضمنا شما یک تابع صریح گذاشتی برای تبدیل به Int و جوابش این بوده؛ یعنی حتی در این حالت تبدیل صریح توسط برنامه نویس هم hello رو به صفر تبدیل نمیکنه!
ولی PHP اصلا همینطوری سرخود کار میکنه و هیچ فایده ای در تفسیر خاصی که داره دیده نمیشه جز حجیم و پیچیده کردن یادگیری و نیاز به دقت بیشتر در موقع برنامه نویسی و افزایش باگها!!
شاید بگی خب بالاخره بهتره خطا بده، چون مثلا ممکنه این مقدار رو مستقیما در دیتابیس درج کنیم و غیره.
ولی خب شاید اینکه خطا نمیده بخاطر اینه که از تابع صریح تبدیل به عدد استفاده کردی، و انتظار اینکه چیزی که بهش میدی اصلا قابل تبدیل به عدد نباشه هم وجود داره بهرحال. یعنی مثل یکجور دستور چک شرطی عمل میکنه در این موارد. یعنی میتونه برای چک کردن اینکه یک رشته ای اصلا قابل تبدیل به عدد هستی یا نه هم استفاده بشه. بهرصورت هم رفتاری که این تابع داره و NaN یک چیز خیلی روشنتر و کم خطرتری هست درکل، چون خیلی احتمالش کمتره که به موارد خطای منطقی و باگها و حفره هایی در برنامه منجر بشه.
  پاسخ
تشکر شده توسط :


پرش به انجمن:


کاربران در حال بازدید این موضوع: 1 مهمان