• 1 رای - 3 میانگین
  • 1
  • 2
  • 3
  • 4
  • 5
طراحی های بد در ساختار زبان PHP
#1
من اظهار میدارم که کیفیات زیر برای پربار ساختن یک زبان مهم هستند، و PHP به شکل بی پروایی از آنها تخلف میکند. اگر شما نمیتوانید با من موافق باشید که این چیزها مهم هستند، خب پس من نمیتوانم تصور کنم که ما هیچوقت روی چیز زیادی توافق داشته باشیم:

- یک زبان باید قابل پیشبینی باشد. آن وسیله ای برای بیان ایده های انسان و اجرا شدن آن ها توسط کامپیوتر است، بنابراین حیاتی است که درک انسان از یک برنامه عملا صحیح باشد.

- یک زبان باید سازگاری داشته باشد. چیزهای مشابه باید مشابه بنظر برسند، چیزهای متفاوت باید متفاوت بنظر برسند. دانستن بخشی از زبان باید در یادگیری و فهم بقیهء آن کمک کند.

- یک زبان باید موجز باشد. زبانهای جدید برای کاهش جزییات جانبی در زبانهای قدیمی بوجود آمده اند (ما همه میتوانستیم کد اسمبلی بنویسیم). یک زبان بنابراین باید تلاش کند از معرفی جزییات جانبی جدید توسط خودش اجتناب کند.

- یک زبان باید قابل اتکا باشد. زبانها ابزارهایی برای حل کردن مسائل هستند؛ آنها باید مسائل جدیدی را که خودشان ایجاد میکنند به حداقل برسانند. هر چیز غیرمنتظره، یک سردرگمی بزرگ است.

- یک زبان باید قابل دیباگ باشد. وقتی چیزی اشتباه پیش میرود، برنامه نویس باید آن را درست کند، و ما به تمام کمکی که میتوانیم بگیریم نیاز داریم.

من بسیار در جریان استدلالهای طرفداران PHP بوده ام. من یک عالمه استدلالهای مخالف عمومی میشنوم که برای آن طراحی شده اند تا فورا به مباحثه خاتمه دهند:

- به من نگویید که «برنامه نویس خوب میتواند با هر زبانی برنامهء خوب بنویسید»، یا «برنامه نویس بد در هر زبانی برنامهء بد مینویسید». آن هیچ معنایی ندارد. یک نجار خوب میتواند یک میخ را با یک سنگ یا چکش بکوبد، اما شما چه تعدادی نجار دیده اید که چیزها را با سنگ میکوبند؟ بخشی از آنچه یک توسعه دهندهء خوب را شکل میدهد، توانایی انتخاب ابزارهاییست که بهتر کار میکنند.

- به من نگوییید «آن وظیفهء برنامه نویس است که هزار استثنای عجیب و غریب و رفتارهای غیرمنتظره را بخاطر بسپارد». بله، این در هر سیستمی لازم است، چون کامپیوترها ابله هستند. اما آن به معنای این نیست که هیچ حداکثری برای میزان بلاهت در یک سیستم وجود ندارد. PHP چیزی نیست جز استثناء ها، و اینکه کشتی گرفتن با زبان تلاش بیشتری از اینکه عملا برنامهء خودتان را بنویسید صرف کند، چیز خوبی نیست. ابزارهای من نباید برای من اینقدر کار اضافه تولید کنند.

- به من نگویید «فیسبوک و ویکیپدیا با PHP درست شده اند». من مطلع هستم! آنها میتوانستند همچنین با زبان Brain**** نوشته شوند، اما تا زمانیکه افراد بقدر کافی باهوشی وجود دارند که میتوانند چیزها را ردیف کنند، آنها میتوانند بر مشکلات پلتفرم غلبه یابند.

فلسفه:

PHP ابتدا صراحتا برای غیربرنامه نویسان (و غیربرنامه ها) طراحی شد. آن هنوز نتوانسته است از ریشه های خودش فرار کند. یک نقل قول متخب از مستندات رسمی PHP2 بعنوان سند این ادعا:
«... بخصوص برای چیزی مثل PHP که بیشتر اسکریپت ها نسبتا ساده خواهند بود و در بیشتر موارد توسط غیربرنامه نویسانی که زبانی با یک سینتاکس پایه که یادگیری آن بیش از حد دشوار و طولانی نباشد میخواهند»

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

Weak typing در PHP (تبدیل خودکار بین رشته ها/اعداد، و غیره) آنقدر پیچیده است که هرچقدر تلاشهای کوچکی از برنامه نویس را کاهش میدهند، ارزشش را ندارد.

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

عملگر == در PHP بلااستفاده است:

این دو مقایسه هر دو درست ارزیابی میشوند:

کد:
"foo" == TRUE

کد:
"foo" == 0

اما مسلما حتی در PHP، صفر با true برابر نیست.

این عبارت درست ارزیابی میشود:

کد:
123 == "123foo"

اما این عبارت غلط ارزیابی میشود:

کد:
"123" == "123foo"

این مقایسه ها درست ارزیابی میشوند:

کد:
"6" == " 6"

کد:
"4.2" == "4.20"

کد:
"133" == "0133"

اما این نه:

کد:
133 == 0133

این ها درست ارزیابی میشوند:

کد:
"0x10" == "16"

کد:
"1e3" == "1000"

هر دوی اینها درست ارزیابی میشوند:

کد:
NULL < -1

کد:
NULL == 0

===========================================

منبع: بخشهایی از http://eev.ee/blog/2012/04/09/php-a-frac...ad-design/

البته من با تمام نظرات و استدلال های این طرف موافق نیستم. بخاطر همین فقط موارد و بخشهایی رو که بنظرم واضحا با اطمینان زیادی درست هستن انتخاب کردم.
بعضی مواردی که طرف بعنوان ضعف های PHP بیان کرده بنظر من میتونن حتی مزیت و نقطهء قوت باشن.
  پاسخ
تشکر شده توسط :
#2
نقل قول:به نظرم شما با فلسفه اسکریپتی مشکل دارید. php بر اساس فلسفه اسکریپت ساخته شده تا بر نوع داده حساس نباشه.
نخیر دوست عزیز من با زبانهای اسکریپتی مشکلی ندارم.
زبانهای اسکریپتی دیگر غیر از PHP فراوان هستن. پایتون و جاوااسکریپت روشن ترین نمونه هاش نزد عموم برنامه نویسان است، ولی تعداد زیاد دیگری هم وجود دارن.
اما هیچکدام از این زبانهای اسکریپتی دیگر اینقدر که PHP در رفتارهای سرخود و خطرآفرین افراط کرده افراط نکردن.
تازه همون حد هم که در زبانهای اسکریپتی دیگر هست بازم بعضیاش محل مناقشه هست و مخالفت ها و استدلال های مخالفی داره.

من خودم استفاده از عملگر == رو تقریبا بطور کامل کنار گذاشتم بجاش از === استفاده میکنم.
حتی پروژهء سیستم رجیستر و لاگین خودم رو که قبلا نوشته بودم برداشتم توی اون همه کد تقریبا تمام == ها رو به === تبدیل کردم، مگر یک مواردی که تغییرش به این سادگی نبود و کدهای دیگری هم باید بررسی و تغییر پیدا میکردن و مشکل جدی هم توش ندیدم.
ضمنا دقیقا یک مورد SQL Injection هم در برنامم شناسایی کردم که بخاطر همین عملگر بوجود آمده بود.
اصولا شما نمیتونید توی برنامه های جدی که خیلی ساده و کم حجم نباشن بصورت پیشفرض از عملگر == برای مقایسه هاتون استفاده کنید! چرا؟ چون استفاده از عملگر == میتونه به سادگی منجر به باگها و حفره های امنیتی در برنامتون بشه که پیشبینی و کنترل اینها از قبل تقریبا غیرممکنه! بخاطر اینکه رفتار عملگر == بیش از حد متنوع و پیچیده است و برنامه نویس باید برای هر مورد در ذهنش ده ها حالت رو بررسی و دقت بکنه در این باب، و این عمل در هنگام برنامه نویس سخت و زمانبر و کاملا مستعد خطاست. صرفه با اینه که از === بجای == استفاده کنیم تا نیازی به این همه دقت و صرف انرژی و متفرق شدن تمرکز برنامه نویس نباشه و در باب امنیت و باگهای برنامه ریسک نکنیم.
همونطور که این مقاله گفته، عملگر == عملا بلااستفاده شده!
انعطاف زبان برنامه نویسی و هوشمندبازی تا یه جایی یه حدی که عاقلانه باشه سودش در کل از ضررش بیشتر باشه، نه اینکه دیگه به اینجا برسه که مثل بمب هر لحظه امکان ترکوندن برنامه رو داشته باشه!!
گفتم زبانهای اسکریپتی دیگر زیاد هستن، ولی شما در هیچکدام این حد از سرخود عمل کردن و افرط رو مشاهده نمیکنید. خواستید میتونیم این نمونه ها رو در زبانهای اسکریپتی دیگری که در دسترس داریم عملا بررسی و تست کنیم تا ببینید که رفتارشون در کل معقول تر و امن تر از PHP است.

ضمنا بنده بعنوان یک متخصص در امور امنیت، دارم این نظر رو بصورت رسمی ابراز میکنم!
اگر به امنیت و کاهش باگهای برنامه هاتون علاقمند هستید، از عملگر == (و همچنین ‎!=‎) تا میتونید دیگه استفاده نکنید!
  پاسخ
تشکر شده توسط :
#3
نقل قول:به نظر من تمام اینایی که گفتین نه تنها ضعف php رو نشون نمیده بلکه حتی برای php نقطه قوت محسوب میشه.
تمام؟!
یعنی جدا مثلا دوتا شرط که با هم متناقض هستن هر دو true ارزیابی میشن، بنظر شما معقوله؟
مثلا: "foo" == TRUE و "foo" == 0. چطور چیزی میتونه هم برابر true باشه و هم برابر صفر؟!
یا این: NULL < -1 و NULL == 0. چطور صفر کوچکتر از -1 میشه؟!

فکر نمیکنم توی هیچ زبان دیگه ای چنین چیزی دیده شده باشه!


نقل قول:عملگر == مخصوص مقادیر عددی هست و استفاده ازش برای مقایسه رشته هایی مثل "356" و "524" نمیتونه منطقی باشه و باید با تابع strcmp این رشته ها مقایسه بشن.
شما دیگه برگشتی به عصر حجر!
بابا strcmp که مال زمان زبان سی بوده!
توی زبانهای سطح بالا و بخصوص اسکریپتی و شاید بخصوص وب، من فکر نمیکنم مقایسه رشته ها با == هیچ اشکالی داشته باشه، بلکه خیلی هم طبیعی و مفیده. در پایتون و جاوااسکریپت هم همینطوره. به خودی خودش مشکلی نداره، بلکه باید اینطور باشه. ولی در تفسیر و تبدیل های خودکار نباید افراط و سرخودکاری زیادی بشه.

نقل قول:ممکنه جایی نیاز بشه بین اعداد 12 و 12.0 تفاوتی وجود نداشته باشه، اون موقع باید از عملگر == استفاده کرد.
بطور کلی بنظر من تبدیل خودکار رشته ها به عدد درست نیست. یعنی دارم البته اینجا درموردی صحبت میکنم که دو طرف هر دو به شکل رشته باشن. حالا اینکه یک طرف رشته باشه یک طرف عدد، بحث و تحلیل جداگانه میطلبه بنظرم.
ببینید، حالا اگر دوتا رشته هر دو محتوی عدد بودن و نه چیز دیگر، باز جای بحث و شک داره، ولی یه موردی مثل "123" == "123foo" بنظر بنده قطعا غلط و غیرقابل قبوله! هیچ شکی نیست که چنین کاری نباید انجام بشه. بعید میدونم توی هیچ زبان دیگری هم چنین چیزی دیده شده باشه. شما خودتون فکر کنید این چیزها چرا توی زبانهای دیگه دیده نشده تاحالا؟ یعنی به فکرشون نرسیده مثلا؟! البته شاید بگید خب چون PHP مخصوص برنامه نویسی وب است، ولی بازم من فکر نمیکنم حتی اینم بتونه عذر کافی باشه برای اینقدر بالا بردن احتمال باگ و حفره های امنیتی برنامه.

نقل قول:لینکی که گذاشتین رو خوندم. خیلی از بخشهاش جالب و نسبتاً هم درست بود ولی خوشبختانه توی PHP7 خیلی از این مشکلات برطرف شدن. دقت کنید که PHP مال زمانی هست که اصلاً شئ گرایی وجود نداشت و بعداً بهش اضافه شد و خیلی از امکانات رو به مرور بهش اضافه کردن و باید توی این مسیر، کاربران قبلی رو هم حفظ میکردن. خیلی از قواعد نامگذاری توی این مدت عوض شدن ولی نمیشد توابع قبلی رو هم تغییر نام داد چون دیگه کدهای قبلی روی نسخه PHP جدید کار نمیکرد. PHP مثل #C نیست چون #C دقیقاً زمانی متولد شد که شئ گرایی به اوج بلوغ خودش رسیده بود و از اول با همون استانداردها تولید شد. توی نسخه 7 خیلی از این ایرادها رفع شده ولی هنوز هم برخی جاها تناقضها و ناسازگاریهایی وجود داره که اگه میخوایم از امکانات و مزایای زیادی که PHP داره و با بی انصافی کامل توی اون مقاله ازش اسمی برده نشده بهره ببریم، ناچاریم باهاشون کنار بیایم و ازشون اطلاع پیدا کنیم که البته تمام این موارد هم توی مستندات سایت رسمی PHP بهشون اشاره شده و اینطور نیست که منبعی برای اینکه بدونیم رفتار فلان عملگر ممکنه عجیب و غریب باشه وجود نداشته باشه.

ازطرفی اومدن و گفتن ساختمانهایی که با اون جعبه ابزار ساخته شده سروته و عجیب و غریبه و در میزنی، از جا در میاد و از این حرفها. کدوم سایتی توی PHP این مدلی بوده؟ سایتهای بزرگ دنیا که با PHP ساخته شدن، واقعاً عجیب و غریبن؟ خیلی از سایتها که روزانه چندین میلیون بازدید دارن (مثل سایت رسمی کاخ سفید و امثال اون) با PHP ساخته شدن و اگه کسی اهل فن نباشه، متوجه هم نمیشه که با PHP ساخته شدن چون مشابه خیلی از سایتهای دیگه دارن بدون مشکل کار میکنن. کجای این نمونه ها، شبیه اون حرفیه که توی مقاله گفته شده؟
البته منم گفتم که با همهء نظرات طرف موافق نیستم. بنظر من همین مواردی که جدا کردم موارد کاملا روشن و جدی هستن. بقیه ایرادهایی که گرفته اونقدر مهم نیستن، مبهم و محل تردید هستن، یا حتی بعضی موارد بنظر من برعکس چیزهای خوبی هستن!
مثلا طرف به آرایه های PHP هم ایراد گرفته ظاهرا گفته مثلا نمیشه میزان حافظه ای رو که مصرف میکنن برآورد کرد بخاطر انعطاف و پیچیدگی زیادی که دارن. ولی بنظر من این ایراد مسخره ایه و انصافا آرایه های PHP بین تمام زبانهایی که تاحالا دیدم منعطف ترین ساختار رو دارن و بنوعی شاهکار هستن که توی برنامه نویسی کار آدم رو خیلی راحت میکنن آدم واقعا لذت میبره. ولی از اون طرف مثلا برآورد حافظه حالا توی این زبانهای سطح بالای اسکریپتی مگه چقدر مسئلهء ضروری و مهمی هست که طرف بهش گیر داده! بنظر من چنین حرفی یخورده مسخره میاد!! حالا اگر از 1000 نفر یکی هم نیاز به این کار داشت، بنظرم از طرق دیگری میتونه میزان حافظه رو برآورد کنه.
  پاسخ
تشکر شده توسط :
#4
نقل قول:در php وقتي از == استفاده ميکنيد اول 2 طرف cast ميشود و بعد شرط بررسي ميشود .

وقتي يک رشته را با عدد 0 بررسي ميکنيد هر 2 از نظر کستينگ برابر است چون مقدار رشته تبديل به int ميشود که همان 0 در نظر گرفته ميشود .
اين مورد براي مقدارهاي Boolean هم صدق ميکنه

براي اينکه عمل کستينگ انجام نشود بايد از === استفاده کنيد يا اينکه قبل از چک کردن خودتان 2 طرف را هم نوع کنيد مثلا براي int با استفاده از تابع intval()

تبديل نوع خودکار منحصر به PHP نيست و در زبانهاي ديگر هم وجود داره. بخصوص زبانهاي اسکريپتي.
ولي اين تبديلات اينطور نيست همينطور هر جور دلشون بخواد باشه. اصول داره.

مثلا اين مثال در جاوااسکريپت:
کد:
<script>
alert(3=="3");
</script>
نتيجه true است.
ولي اين مثال:
کد:
<script>
alert(3=="3foo");
</script>
نتيجه false است.

چرا اينطوره؟
چون رشتهء اول فقط متشکل از رقم است، اما رشتهء دوم حاوي کاراکترهاي غير رقمي است و وجود رقم در ابتداش ميتونه کاملا تصادفي بوده باشه.

چرا اين قاعده رو پياده کردن؟ خب چون مثل PHP اينقدر بي پروا و سرخود نبودن و فکر اينو کردن که بعيده برنامه نويس بخواد چنين چيزهايي رو با هم بصورت عددي مقايسه کنه، و اگر چنين شرايطي رخ ميده، به احتمال بيشتر تصادفيه و بنابراين منطق صحيح که موجب باگ در برنامه نشه اينه که اين عمل تبديل خودکار به چنين صورتي صورت نگيره.

اين فقط يه نمونه بود که خواستم درک کنيد منظور چيه معيار چيه. وگرنه مثال هاي بيشتر هست از زبانهاي مختلف، که نشون ميده همه از PHP محتاط تر و معقول تر عمل ميکنن.

ضمنا جاوااسکريپت هم عملگر === داره.
الان در اين مثال:
کد:
<script>
alert(3==="3");
</script>
نتيجه false است.

يعني متوجه ميشيم که جاوااسکريپت و PHP از اين نظر خيلي به هم نزديک هستن. تنها فرق اينه که عملگر == در PHP هيچ محدوديتي قائل نيست و به زور هم که شده ميخواد هرچي رو که دو طرف هستن تبديل و مقايسه کنه؛ حالا کاري نداره اين رفتار آيا اصلا معقول هست و به دردي ميخوره، آيا در کل بيشتر سودمنده يا مضر و باعث ايجاد باگ در برنامه ها!

بنظر من اين طراحي ها واقعا احمقانه هستن. چون به برنامه نويسي در کل بيشتر از اونچه که بتونن کمک کنن، آسيب ميرسونن.

حال در جاوااسکريپت ما اگر بصورت صريح خودمون درخواست کنيم که رشته به عدد تبديل بشه، مثلا با اين کد:
کد:
<script>
alert(parseInt("3foo"));
</script>
نتيجه و خروجي اين کد عدد 3 است.

اما نتيجهء اين کد:
کد:
<script>
alert(parseInt("foo"));
</script>
NaN ميباشد. يعني ميگه اين رشته قابل تبديل به عدد نيست.

اين مثال نشون ميده که واقعا حساب و قاعده اي اين وسط وجود داره مسائلي رو در نظر گرفتن که در PHP در نظر گرفته نشدن.
اون قاعده چيه؟ در مثال اول، چون برنامه نويس خودش صريحا درخواست کرده رشته به عدد تبديل بشه، بنابراين زبان ميتونه تلاش کنه تا رشته رو به هر صورت ممکن و معناداري به عدد تبديل کنه، و ميتونه اطمينان بيشتري داشته باشه که با اينکه کاراکترهاي غيررقمي هم بعد از کاراکتر رقمي وجود دارن اما برنامه نويس از اين مسئله مطلع بوده و بخاطر همين از اين تابع استفاده کرده.
اما جاوااسکريپت عاقل است، و در مقايسه ها (عملگر ==) اينطور مطمئن عمل نميکنه و مثلا 3foo رو به 3 تبديل نميکنه، چون در اونجا درخواست صريحي از جانب برنامه نويس وجود نداره و وجود 3 در ابتداي چنين رشته اي به احتمال بيشتر تصادفي است تا اينکه واقعا معنادار باشه.
و اما در مثال دوم، مشاهده ميکنيم که جاوااسکريپت حتي يک درجه از اين هم محتاط تر هست و رشته اي رو که حاوي هيچ کاراکتر رقمي نيست به صفر تبديل نميکنه. و شما اگر فکر کنيد هم، خب احتمال بيشتر اينه که برنامه نويس هم قصدش اين نبوده يه همچين رشته اي به عدد صفر تبديل بشه! اين رشته رو از کجا آورده و چرا ميخواد تبديل به عدد صفر بشه؟ بهرحال هم اگر هدف برنامه نويس واقعا اين بوده باشه که رشته هاي کاملا غيرعددي به صفر تبديل بشن، ميتونه خودش براي مقدار NaN چک کنه و اگر مقدار برگشتي NaN بود، مقدار صفر رو به متغيير بده. اينطوري عمل بصورت آگاهانه توسط خود برنامه نويس انجام ميشه و ريسک رفتار غيرمنتظره و ايجاد باگ در برنامه وجود نداره.

نقل قول:وقتی یک رشته را با عدد 0 بررسی میکنید هر 2 از نظر کستینگ برابر است چون مقدار رشته تبدیل به int میشود که همان 0 در نظر گرفته میشود.
خب چرا عدد رو به رشته تبدیل نمیکنه و دو طرف رو بصورت رشته ای مقایسه کنه؟
یعنی همینطوری رندوم تصمیم گرفتن که هرجا یک طرف رشته بود و یک طرف عدد، رشته رو به عدد تبدیل کنن و دو طرف رو بصورت عددی مقایسه کنن؟
بنظر من اگر تبدیل به رشته میکرد، خیلی امن تر میبود، چون اونوقت دیگه 3foo با 3 برابر نمیشد.
  پاسخ
تشکر شده توسط :


پرش به انجمن:


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