لماذا تكون طريقة __set() الفارغة أبطأ من الطريقة التي تعمل؟
-
21-12-2019 - |
سؤال
كنت أتلاعب بأساليب PHP السحرية (على وجه التحديد التحميل الزائد على الممتلكات)، وأثناء إجراء المقارنة المعيارية الدقيقة، واجهت مشكلة أواجه صعوبة في شرحها:
ويبدو أن أ __set
تستغرق الطريقة ذات النص الفارغ وقتًا أطول للتشغيل من الطريقة التي تعمل.يوضح مقتطف الكود أدناه هذا:
class EmptySetter {
public function __set($name, $value) {}
}
class NonEmptySetter {
public function __set($name, $value) {
$this->{$name} = $value;
}
}
function benchmark($obj) {
$start_time = microtime(TRUE);
for ($i = 0; $i < 10000000; $i++) {
$obj->foo = 42;
}
return microtime(TRUE) - $start_time;
}
printf("EmptySetter: %.2f seconds\n", benchmark(new EmptySetter));
printf("NonEmptySetter: %.2f seconds\n", benchmark(new NonEmptySetter));
// output (on my Core 2 Duo laptop):
// EmptySetter: 4.39 seconds
// NonEmptySetter: 1.28 seconds
هل لدى أي شخص تفسير لماذا يحدث هذا؟
المحلول
أوه، أرى أنها حالة اختبار خاطئة.
بعد الحلقة الأولى NonEmptySetter
سيكون لديه ممتلكات عامة جديدة foo
.الحلقات التالية لا تتصل __set
الطريقة على الإطلاق، يستخدمون الملكية العامة.
class NonEmptySetter {
public function __set($name, $value) {
echo 'called only once'; // would be echoed only once.
$this->{$name} = $value;
}
}
اختبار صالح
class EmptySetter {
public function __set($name, $value) {}
}
class NonEmptySetter {
public function __set($name, $value) {
$this->{$name} = $value;
}
}
function benchmark($class_name) {
$start_time = microtime(TRUE);
for ($i = 0; $i < 1000000; $i++) {
$obj = new $class_name();
$obj->foo = 42;
}
return microtime(TRUE) - $start_time;
}
printf("NonEmptySetter: %.2f seconds\n", benchmark('NonEmptySetter'));
printf("EmptySetter: %.2f seconds\n", benchmark('EmptySetter'));
أداة الضبط الفارغة أسرع.
نصائح أخرى
لا يمكنك المقارنة بين هذين، لأن النتيجة النهائية ليست متساوية.
$o1 = (new NonEmptySetter);
$o1->foo = 42;
$o2 = (new EmptySetter);
$o2->foo = 42;
var_dump($o1, $o2, $o2->foo);
هذا يعطي:
object(NonEmptySetter)[1]
public 'foo' => int 42
object(EmptySetter)[2]
null
بالإضافة إلى ملاحظة للأخيرة: Notice: Undefined property: EmptySetter::$foo
وهذا يعني لم يتم تعيين الخاصية أبدًا, ، إنه غير موجود، أيها الغبار الخيالي، أفترض أن المخالفات هناك تستغرق وقتًا.
إذا أعلنت صفك بشكل صحيح (لاحظ $foo
):
class EmptySetter {
public $foo = NULL;
public function __set($name, $value) {}
}