سؤال

لقد كنت استخدم eval سمة من روبي عدة مرات.لكني سمعت الناس يقولون evalإنها سيئة.عندما سُئلت لماذا وكيف، لم أتمكن أبدًا من الحصول على سبب مقنع لعدم استخدامه.هل هم حقا سيئة؟إذا كانت الإجابة بنعم، ما هي الطريقة؟ما هي الخيارات الممكنة "الأكثر أمانًا" للتقييم؟

هل كانت مفيدة؟

المحلول

إذا كنت evaling سلسلة مقدمة من قبل، أو للتعديل من قبل المستخدم، وهذا هو بمثابة السماح بتنفيذ تعليمات برمجية عشوائية. تخيل لو احتوت سلسلة مكالمة OS لrm -rf / أو ما شابه ذلك. وقال، في الحالات التي تعرف مقيدة السلاسل بشكل مناسب، أو سندبوإكسد روبي مترجم بشكل مناسب، أو مثاليا على حد سواء، ويمكن eval تكون قوية للغاية.

والمشكلة هي مماثلة ل حقن SQL ، إذا كنت على دراية. الحل هنا هو مماثل لحل لمشكلة حقن (استعلامات معلمات). وهذا هو، إذا كانت البيانات التي تريد من المعروف أن من شكل محدد للغاية لeval، وليس <م> جميع بيان من الضروري أن تقدم من قبل المستخدم، سوى عدد قليل من المتغيرات، التعبير الرياضيات، أو ما شابه ذلك، يمكنك أن تأخذ في هذه القطع الصغيرة من المستخدم، تطهير عليها إذا لزم الأمر، ثم تقييم بيان قالب آمن مع إدخال المستخدم في الوتر في الأماكن المناسبة.

نصائح أخرى

يوجد في روبي العديد من الحيل التي قد تكون أكثر ملاءمة منها eval():

  1. هنالك #send والذي يسمح لك باستدعاء الأسلوب الذي لديك اسمه كسلسلة وتمرير المعلمات إليه.
  2. yield يسمح لك بتمرير كتلة من التعليمات البرمجية إلى الطريقة التي سيتم تنفيذها في سياق طريقة الاستلام.
  3. في كثير من الأحيان بسيطة Kernel.const_get("String") يكفي للحصول على الفصل الذي لديك اسمه كسلسلة.

أعتقد أنني غير قادر على شرحها بشكل صحيح بالتفصيل، لذلك قدمت لك التلميحات فقط، إذا كنت مهتمًا، فابحث في Google.

eval ليس فقط غير آمن (كما تمت الإشارة إليه في مكان آخر)، بل إنه بطيء أيضًا.في كل مرة يتم تنفيذها، يتم تشغيل AST الخاص بـ evalيجب تحليل كود ed (وعلى سبيل المثال JRuby، تحويله إلى bytecode) من جديد، وهي عملية ثقيلة السلسلة ومن المحتمل أيضًا أن تكون سيئة بالنسبة لذاكرة التخزين المؤقت المحلية (على افتراض أن البرنامج قيد التشغيل لا eval كثيرًا، وبالتالي فإن الأجزاء المقابلة من المترجم تكون باردة في ذاكرة التخزين المؤقت، بالإضافة إلى كونها كبيرة الحجم).

لماذا هناك eval على الإطلاق في روبي، تسأل؟"لأننا نستطيع" في الغالب - في الواقع، متى eval تم اختراعه (للغة البرمجة LISP)، كان كذلك في الغالب للعرض!أكثر إلى هذه النقطة، وذلك باستخدام eval هو الشيء الصحيح عندما تريد "إضافة مترجم فوري إلى مترجمك الفوري"، لمهام البرمجة الوصفية مثل كتابة معالج مسبق أو مصحح أخطاء أو محرك قوالب.الفكرة الشائعة لمثل هذه التطبيقات هي تدليك بعض أكواد روبي والاتصال بها eval عليه، ومن المؤكد أنه يتفوق على إعادة اختراع وتنفيذ لغة ألعاب خاصة بمجال معين، وهو مأزق يُعرف أيضًا باسم القاعدة العاشرة لجرينسبان.المحاذير هي:احذر من التكاليف، على سبيل المثال بالنسبة لمحرك القوالب، افعل كل ما عليك evalجي في وقت بدء التشغيل وليس وقت التشغيل؛ولا تفعل ذلك eval كود غير موثوق به إلا إذا كنت تعرف كيفية "ترويضه"، أي تحديد وفرض مجموعة فرعية آمنة من اللغة وفقًا لنظرية الانضباط القدرة.هذا الأخير هو أ كثير من العمل الصعب حقا (انظر على سبيل المثال كيف تم ذلك لجافا;لست على علم بأي جهد من هذا القبيل بالنسبة لروبي للأسف).

ويجعل التصحيح صعوبة. فإنه يجعل من الصعب الأمثل. ولكن الأهم من ذلك كله، انها عادة ما تكون علامة على أن هناك طريقة أفضل للقيام بكل ما تحاول القيام به.

إذا كنت تقول لنا ما تحاول تحقيقه مع eval، قد تحصل على بعض الإجابات أكثر ذات العلاقة بالموضوع السيناريو الخاص بك محددة.

وحدة التقييم هي ميزة قوية بشكل لا يصدق التي ينبغي استخدامها بعناية. وعلاوة على ذلك أشارت القضايا الأمنية بها مات J، وسوف تجد أيضا أن التعليمات البرمجية التصحيح وقت تقييمها من الصعب للغاية. وهناك مشكلة في كتلة كود وقت تقييمها يكون من الصعب على المترجم للتعبير - لذلك سوف تبحث عن ذلك يكون من الصعب

وأن يقال، إذا كنت مرتاحا مع هذه المسألة، ونحن لا تشعر بالقلق إزاء قضية أمنية، ثم يجب أن لا تجنب استخدام واحدة من الميزات التي تجعل روبي كما جذابة كما هو.

في بعض الحالات، وeval في وضع جيد وذكي ويقلل من كمية من التعليمات البرمجية المطلوبة. بالإضافة إلى المخاوف الأمنية التي تم ذكرها من قبل مات J، تحتاج أيضا أن تسأل نفسك سؤال واحد بسيط جدا:

عند يقال كل ما والقيام به، ويمكن لأي شخص آخر قراءة التعليمات البرمجية الخاصة بك وفهم ما فعلت؟

إذا كان الجواب بالنفي، ثم ما كنت قد اكتسبت مع eval وتخلى عن الصيانة. هذه المسألة ليست فقط قابلة للتطبيق إذا كنت تعمل في الفريق، ولكنه أيضا ينطبق عليك - أنت تريد أن تكون قادرة أن ننظر إلى الوراء في كود أشهر، إذا لم يكن سنوات من الآن، ومعرفة ما فعلتم

إذا كنت تمر أي شيء التي تحصل عليها من "الخارج" لeval، يا تفعل شيئا خطأ، وانها سيئة للغاية. انها <م> جدا من الصعب الهروب رمز بما فيه الكفاية من أجل أن تكون آمنة، لذلك كنت تنظر فيه غير آمنة تماما. ومع ذلك، إذا كنت تستخدم وحدة التقييم لتجنب الازدواجية أو غيرها من الأمور المشابهة، مثل مثال التعليمة البرمجية التالية، كل شيء على مايرام لاستخدامها.

class Foo
  def self.define_getters(*symbols)
    symbols.each do |symbol|
      eval "def #{symbol}; @#{symbol}; end"
    end
  end

  define_getters :foo, :bar, :baz
end

ولكن، على الأقل في Ruby 1.9.1، روبي لديها أساليب البرمجة الفوقية قوية حقا، ويمكنك أن تفعل ما يلي بدلا من ذلك:

class Foo
  def self.define_getters(*symbols)
    symbols.each do |symbol|
      define_method(symbol) { instance_variable_get(symbol) }
    end
  end

  define_getters :foo, :bar, :baz
end

لمعظم الأغراض، وكنت ترغب في استخدام هذه الأساليب، وليس هناك حاجة الفرار.

والشيء السيء آخر عن eval هو حقيقة أن (على الأقل في روبي)، انها بطيئة جدا، كما المترجم يحتاج إلى تحليل سلسلة، ومن ثم تنفيذ التعليمات البرمجية داخل الربط الحالي. أساليب أخرى باستدعاء الدالة C مباشرة، وبالتالي يجب أن تحصل على قليل من زيادة السرعة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top