Вчера в IRC на одном из каналов, которые я посещаю, зашёл очередной holywar на тему «Почему переменные в PHP, определённые в циклах, не остаются видимыми только в области цикла, а становятся видны и поза циклом?».
Я решил провести маленькую проверку на аналогичные вещи в других языках.
Насколько я знаю, в Perl как раз наоборот PHP-переменные, определённые внутри тела цикла, видны только в пределах цикла. И подтверждение этому следующий код:
my $a = 0; for (my $a = 0; $a < 3; $a++) { } print $a, "n";
Ниже привожу фрагменты кода, что получились на c, c++, java, javascript:
c++:
#include <iostream> #include <string> using namespace std; int main(int argc, char *argv[ ] ) { int a = 0; for (int a=0; a <= 2; a++ ) { } cout << "test a=" << a << endl; }
c:
java:#include <iostream> #include <string> int main() { int a = 0; for (int a=0; a<= 2; a++ ) {} sprint("[%s]", a); }
public class testScope { public static void main(String[] args) { int a = 0; for (int a = 0; a < 3; a++) {} System.out.println(a); } }
javascript:
var a = 0; for (var a = 0; a < 3; a++) {} alert(a);
Каковы итоги? Довольно неожиданны оказались для тех, кто утверждал, что такая реализация только в PHP.
Результаты:
Javascipt: вывел 3.
Java: ошибка на этапе компиляции: область внутри цикла является глобальной, поэтому переопределение ранее определённой переменной невозможно.
(cannot rediclare a)
C++: вывод на экран: test a=0
С: ошибка на этапе компиляции: область внутри цикла является глобальной, поэтому переопределение ранее определённой переменной невозможно.
(a.c:7: error: redefinition of ‘a’
a.c:6: error: previous definition of ‘a’ was here)
Код для с, с++ писался под FreeBSD, компилировался gcc и g++ соответственно. Для java был использован Eclipse. Javascript — Edit+ + браузеры.
Оказывается, что так, как это работает в Perl, так работает ещё только в c++, а, следовательно, PHP не является «еретиком» в плане такого поведения — он всего лишь «один из многих». А вот хорошо или плохо такое поведение — это уже, наверное, вопрос не этой заметки.
Автор: Станислав Малкин.
Интересное...
Комментарии:
Vyazovoi Says:
30.09.2007 в 20:43
А в чем собственно минус? Если сильно надо будет можно сделать unset
хотя я нуб, тонкостей незнаю, но вот узнать интересно.
anycolor Says:
30.09.2007 в 20:55
Vyazovoi, минус в засорении глобальной области видимости - и как результат - появление ошибок.
Vyazovoi Says:
30.09.2007 в 21:33
если давать уникальные имена переменным ошибок небудет ) Или взять за привычку делать ансет, хотя впринципе да - должно быть наоборот.
anycolor Says:
30.09.2007 в 21:54
Vyazovoi, unset это почти тоже самое, что в языке программирования следить за динамически выделяемой памятью - сколько не следи, все равно появляются ошибки. Поэтому unset - это вариант, но не очень хорошее решение.
Ni@m Says:
01.10.2007 в 00:25
Насчёт php - это действительно плохо. =/.
Засорение памяти, пространства имён и т.д.
Дело в том, что, насколько мне известно, php-интерпретатор не следит за ссылками на переменные - и если много подобных циклов и переменные везде разные имена имеют - ну тогда не шибко хорошо, хотя если корректно использовать функциональное программирование или ООП - то все будет гут.
Было сказано, что о такой как и все - не совсем - c, java - отказываются компилировать такой код - и правильно.
Видимостью переменной определённой внутри цикла вне его страдает ещё python и ruby - но им “простительно” - они корректно считают ссылки на свои переменные, таким образом память не загрязняется.
А с++/perl повели самым достойным образом - область видимость - это область видимости. =)
Dmitry Zhariy Says:
01.10.2007 в 15:28
В С++ очень активно используется автоуничтожение (автовызов его деструктора) при выходе из области видимости объекта.
Для С++ это очень важно… В Перле же я это свойство использовал в жизни только один раз. Пару минут назад, когда хотел попробывать, что оно работает :)
Вот код:
MyClass.pm
package MyClass;
sub new {
print "I am constructor!\n";
return bless {};
}
sub say_hello() {
print "Hello!!!\n";
}
sub DESTROY {
print "I am destructor!\n";
}
1;
test.pluse MyClass;
use strict;
print "-" x 10, "This is the start!\n";
if (1) {
my $object = new MyClass();
$object->say_hello();
}
print "-" x 10,"This is the end";
Output:----------This is the start!
I am constructor!
Hello!!!
I am destructor!
----------This is the end
Комментариев нет:
Отправить комментарий