Sep
30
|
Об областях видимости в языках программирования.
|
Вчера в 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:
#include <iostream>
#include <string>
int main() {
int a = 0;
for (int a=0; a<= 2; a++ ) {}
sprint("[%s]", a);
}
java:
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 не является “еретиком” в плане такого поведения – он всего лишь “один из многих”. А вот хорошо или плохо такое поведение – это уже наверное вопрос не этой заметки.
30.09.2007 в 20:43
А в чем собственно минус? Если сильно надо будет можно сделать unset
хотя я нуб, тонкостей незнаю, но вот узнать интересно.
30.09.2007 в 20:55
Vyazovoi, минус в засорении глобальной области видимости – и как результат – появление ошибок.
30.09.2007 в 21:33
если давать уникальные имена переменным ошибок небудет ) Или взять за привычку делать ансет, хотя впринципе да – должно быть наоборот.
30.09.2007 в 21:54
Vyazovoi, unset это почти тоже самое, что в языке программирования следить за динамически выделяемой памятью – сколько не следи, все равно появляются ошибки. Поэтому unset – это вариант, но не очень хорошее решение.
01.10.2007 в 00:25
Насчёт php – это действительно плохо. =/.
Засорение памяти, пространства имён и т.д.
Дело в том, что, насколько мне известно, php-интерпретатор не следит за ссылками на переменные – и если много подобных циклов и переменные везде разные имена имеют – ну тогда не шибко хорошо, хотя если корректно использовать функциональное программирование или ООП – то все будет гут.
Было сказано, что о такой как и все – не совсем – c, java – отказываются компилировать такой код – и правильно.
Видимостью переменной определённой внутри цикла вне его страдает ещё python и ruby – но им “простительно” – они корректно считают ссылки на свои переменные, таким образом память не загрязняется.
А с++/perl повели самым достойным образом – область видимость – это область видимости. =)
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.pl
use 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