16297

Объектно-ориентированное программирование на РНР

Лабораторная работа

Информатика, кибернетика и программирование

ЛАБОРАТОРНАЯ РАБОТА №8 Объектноориентированное программирование на РНР PHP и ООП. Хотя РНР обладает общими объектноориентированными возможностями он не является полноценным ООязыком например таким как C или Java. В частности в РНР не поддерживаются следующие объ...

Русский

2013-06-20

44.84 KB

11 чел.

ЛАБОРАТОРНАЯ РАБОТА №8

Объектно-ориентированное программирование на РНР

PHP и ООП.

Хотя РНР обладает общими объектно-ориентированными возможностями, он не является полноценным ОО-языком (например, таким, как C++ или Java). В частности, в РНР не поддерживаются следующие объектно-ориентированные возможности: 

множественное наследование;

автоматический вызов конструкторов (если вы хотите, чтобы при конструировании объекта производного класса вызывался конструктор базового класса, вам придется вызвать его явно);

абстрактные классы;

перегрузка методов;

перегрузка операторов (это связано с тем, что РНР является языком со свободной типизацией);

закрытый и открытый доступ, виртуальные функции;

деструкторы.

Но и без всего перечисленного вы все равно сможете извлечь пользу из объектно-ориентированных возможностей, поддерживаемых РНР. Реализация ООП в РНР оказывает колоссальную помощь в модульном оформлении функциональности вашей программы. 

  1.  
    Классы, объекты и объявления методов.



Классы образуют синтаксическую базу объектно-ориентированного программирования. Их можно рассматривать как своего рода "контейнеры" для логически связанных данных и функций (методов). Класс представляет собой шаблон, по которому создаются конкретные экземпляры, используемые в программе. Экземпляры классов называются объектами. 

Класс также можно рассматривать как тип данных, а объект — как переменную (по аналогии с тем, как переменная $counter относится к целому, а переменная $last_name — к строковому типу). Программа может одновременно работать с несколькими объектами одного класса как с несколькими переменными целого типа. Общий формат классов РНР приведен в листинге 1. 


Листинг 1. Объявление классов в РНР. 

class Class_name {

var $attribute_1;

//...

var $attribute_N;

function function1() {

//...

}

//...

function functionN() {

//...

}

} // end Class_name 


Подведем итоги: объявление класса должно начинаться с ключевого слова class (подобно тому, как объявление функции начинается с ключевого слова function). Каждому объявлению атрибута, содержащегося в классе, должно предшествовать ключевое слово var. Атрибуты могут относиться к любому типу данных, поддерживаемых в РНР. После объявлений атрибутов следуют объявления методов, очень похожие на типичные объявления функций. 

Методы часто используются для работы с атрибутами классов. При ссылках на атрибуты внутри методов используется специальная переменная $this. Синтаксис методов продемонстрирован в следующем примере: 



class Webpage {

var $bgcolor;

function setBgColor($color) {

$this->bgcolor = $color;

}

function getBgColor() {

return $this->bgcolor;

}

}

?> 


Переменная $this ссылается на экземпляр объекта, для которого вызывается метод. Поскольку в любом классе может существовать несколько экземпляров объектов, уточнение $this необходимо для ссылок на атрибуты, принадлежащие текущему объекту. При использовании этого синтаксиса обратите внимание на два обстоятельства: 

атрибут, на который вы ссылаетесь в методе, не нужно передавать в виде параметра функции;

знак доллара ($) ставится перед переменной $this, но не перед именем атрибута (как у обычной переменной).


3. Создание объектов и работа с ними.


Объекты создаются оператором new. Например, объект класса Webpage создается следующей командой: 

$some_page = new Webpage; 


Новый объект с именем $some_page обладает собственным набором атрибутов и методов, перечисленных в классе Webpage. Для изменения значения атрибута $bgcolor, принадлежащего этому конкретному объекту, можно воспользоваться определенным в классе методом setBgColor( ): 

$some_page->setBgColor("black"); 


Следует помнить, что РНР также позволяет явно получить значение атрибута указанием имен объекта и атрибута: 

$some_page->bgcolor="black"; 


Однако второй способ противоречит принципу инкапсуляции, и при работе с ООП поступать так не следует. 


4. Нарушение инкапсуляции.


Допустим, вы создали класс, один из атрибутов которого представляет собой массив. Но вместо того чтобы работать с массивом через промежуточные методы (например, предназначенные для создания, удаления, модификации элементов и т. д.), вы в случае необходимости напрямую обращаетесь к массиву. В течение месяца вы уверенно программируете большое "объектно-ориентированное". 

Но вот через месяц после успешного запуска вашего web-приложения Вы вдруг решаете, что массивы в данном случае не годятся и работать с информацией нужно только через базу данных. 

Поскольку вы решили работать с атрибутами напрямую, вам теперь придется просматривать всю программу и везде, где происходят обращения к данным, вносить исправления в соответствии с новым интерфейсом. Задача весьма хлопотная, к тому же чревата риском внесения новых ошибок. 

А теперь давайте посмотрим, что произошло бы при работе с данными с использованием методов. Все, что вам пришлось бы сделать при переходе от массива к базе данных — перепрограммировать методы. Модификация автоматически распространяется на все точки программы, в которых присутствуют вызовы методов. 


5. Конструкторы.


Довольно часто при создании объекта требуется задать значения некоторых атрибутов. К счастью, разработчики технологии ООП учли это обстоятельство и реализовали его в концепции конструкторов. Конструктор представляет собой метод, который задает значения некоторых атрибутов (а также может вызывать другие методы). Конструкторы вызываются автоматически при создании новых объектов. Чтобы это стало возможным, имя метода-конструктора должно совпадать с именем класса, в котором он содержится. Пример конструктора приведен в листинге 2. 


Листинг 2. Использование конструктора. 


class Webpage {

var $bgcolor;

function Webpage($color) {

$this->bgcolor = $color;

}

}

// Вызвать конструктор класса Webpage

$page = new Webpage("brown");

?> 


Раньше создание объекта и инициализация атрибутов выполнялись раздельно. Конструкторы позволяют выполнить эти действия за один этап. 

Интересная подробность: в зависимости от количества передаваемых параметров могут вызываться разные конструкторы. Например, в листинге 2 объекты класса Webpage могут создаваться двумя способами. Во-первых, вы можете вызвать конструктор, который просто создает объект, но не инициализирует его атрибуты: 

$page = new Webpage; 


Во-вторых, объект можно создать при помощи конструктора, определенного в классе, — в этом случае вы создаете объект класса Webpage и присваиваете значение его атрибуту bgcolor: 

$page = new Webpage("brown"); 


6. Деструкторы.


Как упоминалось ранее, в РНР отсутствует непосредственная поддержка деструкторов. Тем не менее, вы можете легко имитировать работу деструктора, вызывая функцию РНР unset( ). Эта функция уничтожает содержимое переменной и возвращает занимаемые ею ресурсы системе. С объектами unset( ) работает так же, как и с переменными. Допустим, вы работаете с объектом $Webpage. После завершения работы с этим конкретным объектом вызывается функция: 

unset($Webpage); 


Эта команда удаляет из памяти все содержимое $Webpage. Действуя в духе инкапсуляции, можно поместить вызов unset( ) в метод с именем destroy( ) и затем вызвать его: 

$Webpage->destroy( ); 


Необходимость в вызове деструкторов возникает лишь при работе с объектами, использующими большой объем ресурсов, поскольку все переменные и объекты автоматически уничтожаются по завершении сценария. 


7. Простое и иерархическое наследование.


Наследование является исключительно полезным средством программирования, поскольку его применение предотвращает копирование кода, совместно используемого структурами данных. В общем случае синтаксис наследования характеристик другого класса в РНР выглядит так: 


class Class_name2 extends Class_name1 { 

объявления атрибутов; 

объявления методов; 

} 


Ключевое слово extends говорит о том, что класс Class_name2 наследует все характеристики класса Class_name1. 

Помимо возможности многократного использования кода, наследование обладает еще одним важным преимуществом — снижается вероятность ошибок при модификации программы. Например, в иерархии, изображенной на рис. 6.1, изменения в классе "автомобиль" никак не отразятся на коде (и данных) класса "самолет", и наоборот. 

Вызов конструктора производного класса не приводит к автоматическому вызову конструктора базового класса. 

class Class_name2 extends Class_name1 {

//объявления атрибутов;

//объявления методов;

} 


В листинге 3 приведены классы, моделирующие иерархию транспортных средств. 


Листинг 3. Представление различных типов транспортных средств при помощи наследования. 


// Транспортное средство

class Vehicle {

var $model;

var $current_speed;

function setSpeed($mph) {

$this->current_speed = $mph;

}

function getSpeed() {

return $this->current_speed;

}

}

// Автомобиль

class Auto extends Vehicle { 

var $fuel_type;

function setFuelType($fuel) {

$this->fuel_type = $fuel;

}

function getFuelType() {

return $this->fuel_type;

}

}

// Самолет

class Airplane extends Vehicle {

var $wingspan;

function setWingSpan($wingspan) {

$this->wingspan = $wingspan;

}

function getWingSpan() {

return $this->wingspan;

}

}

?> 


Объекты этих классов создаются следующим образом: 

$tractor = new Vehicle;

$gulfstream = new Airplane; 


Приведенные команды создают два объекта. Первый объект, $tractor, относится к классу Vehicle. Второй объект, $gulfstream, относится к классу Airplane и потому обладает как общими характеристиками класса Vehicle, так и уточненными характеристиками класса Airplаne. 

Ситуация, при которой класс наследует свойства нескольких родительских классов, называется множественным наследованием. К сожалению, в РНР множественное наследование не поддерживается. Например, следующая конструкция невозможна в РНР: 

class Airplane extends Vehicle extends Building... 


7. Многоуровневое наследование.


С увеличением размеров и сложности программ может возникнуть необходимость в многоуровневом наследовании. Иначе говоря, класс будет наследовать свои свойства от других классов, которые, в свою очередь, будут наследовать от третьих классов и т. д. Многоуровневое наследование развивает модульную структуру программы, обеспечивая простоту сопровождения и более четкую логическую структуру. Скажем, при использовании примера с транспортными средствами в большой программе может появиться необходимость в дополнительном разбиении на субклассы суперкласса Vehicle, продолжающем логическое развитие иерархии. Например, транспортные средства можно дополнительно разделить на наземные, морские и воздушные, чтобы суперкласс специализированных субклассов выбирался в зависимости от среды, в которой перемещается данное транспортное средство. 

Краткий пример, приведенный в листинге 4, подчеркивает некоторые важные аспекты многоуровневого наследования в РНР. 


Листинг 4. Многоуровневое наследование 


class Vehicle {

//Объявления атрибутов...

//Объявления методов...

}

class Land extends Vehicle {

//Объявления атрибутов...

//Объявления методов...

}

class Car extends Land {

//Объявления атрибутов...

//Объявления методов...

}

$nissan = new Car;

?> 


Объект $nissan содержит все атрибуты и методы классов Саr, Land и Vehicle. Как видите, программа получается исключительно модульной. Допустим, когда-то в будущем вы захотите добавить в класс Land новый атрибут. Нет проблем: внесите соответствующие изменения в класс Land, и этот атрибут немедленно становится доступным для классов Land и Саr, не влияя на функциональность других классов. Таким образом, модульность кода и гибкость относятся к числу основных преимуществ ООП. 


8. Абстрактные классы.


В некоторых ситуациях бывает удобно создать класс, объекты которого никогда не создаются (данный класс нужен всего лишь как базовый для создания производных классов). Такие классы называются абстрактными. Абстрактные классы обычно применяются в тех случаях, когда разработчик программы хочет обеспечить обязательную поддержку некоторых функциональных возможностей всеми классами, производными от абстрактного базового класса. 

В РНР отсутствует прямая поддержка абстрактных классов, однако существует простое обходное решение — достаточно определить в "абстрактном" классе конструктор и включить в него вызов die( ). Вернемся к классам из листинга 4. Скорее всего, вам никогда не придется создавать экземпляры классов Land и Vehicle, поскольку они не могут представлять физические объекты. Для представления реальных объектов (например, автомобилей) следует создать класс, производный от этих классов. Следовательно, чтобы предотвратить возможное создание объектов классов Land и Vehicle, необходимо включить в их конструкторы вызовы die( ), как показано в листинге 5. 


Листинг 5. Создание абстрактных классов. 


class Vehicle {

//Объявления атрибутов...

function Vehicle() {

die ("Cannot create Abstract Vehicle class!");

}

//Объявления других методов...

}

class Land extends Vehicle {

//Объявления атрибутов...

function Land() {

die ("Cannot create Abstract Land class!");

}

//Объявления других методов. 

}

class Car extends Land {

//Объявления атрибутов...

//Объявления методов...

}

?> 


Попытка создания экземпляра этих абстрактных классов приведет к выдаче сообщения об ошибке и завершению программы. 


9. Перегрузка методов.


Перегрузкой методов называется определение нескольких методов с одинаковыми именами, но разным количеством или типом параметров. Как и в случае с абстрактными классами, в РНР эта возможность не поддерживается, но существует простое обходное решение, приведенное в листинге 6. 


Листинг 6. Перегрузка методов. 


class Page {

var $bgcolor;

var $textcolor;

function Page() {

// Определить количество переданных аргументов

// и вызвать метод с нужным именем

$name = "Page".func_num_args();

// Call $name with correct number of arguments passed in

if ( func_num_args() == 0 ) :

$this->$name();

else :

$this->$name(func_get_arg(0));

endif;

}

function Page0() {

$this->bgcolor = "white";

$this->textcolor = "black";

print "Created default page";

}

function Page1($bgcolor) {

$this->bgcolor = $bgcolor;

$this->textcolor = "black";

print "Created custom page";

}

}

$html_page = new Page("red");

?> 


В этом примере при создании нового объекта с именем $html_page передается один аргумент. Поскольку в классе был определен конструктор по умолчанию (Раgе( )), вызывается именно он. Однако конструктор по умолчанию всего лишь выбирает, какому из конструкторов (Page0( ) или Page1( )) следует передать управление. При выборе конструктора используются функции func_num_args( ) и func_get_arg( ), которые, соответственно, определяют количество аргументов и читают эти аргументы. 

Конечно, такое решение вряд ли можно назвать полноценной перегрузкой, но оно подойдет для тех, кто не может жить без этого важного аспекта ООП. 


10. Функции для работы с классами и объектами.


В РНР существует несколько стандартных функций для работы с классами и объектами. Все они часто используются на практике, особенно в процессе разработки интерфейса, администрирования кода и диагностики ошибок. 


get_class_methods( ).


Функция get_class_methods( ) возвращает массив имен методов класса с заданным именем. Синтаксис функции get_class_methods( ): 

array get_class_methods (string имя_класса) 

Простой пример использования get_class_methods( ) приведен в листинге 7. 


Листинг 7. Получение списка методов класса. 


//...

class Airplane extends Vehicle {

var $wingspan;

function setWingSpan($wingspan) {

$this->wingspan = $wingspan;

}

function getWingSpan() {

return $this->wingspan;

}

}

$cls_methods = get_class_methods("Airplane");

// Массив $cls_methods содержит имена всех методов,

// объявленных в классах "Airplane" и "Vehicle"

?> 


Как видно из листинга 7, функция get_class_methods( ) позволяет легко получить информацию обо всех методах, поддерживаемых классом. 


get_class_vars( ).


Функция get_class_vars( ) возвращает массив имен атрибутов класса с заданным именем. Синтаксис функции get_class_vars( ): 

array get_class_vars (string имя_класса) 

Пример использования get_class_vars( ) приведен в листинге 8. 


Листинг 8. Получение списка атрибутов класса функцией get_class_vars( ). 


class Vehicle {

var $model;

var $current_speed;

}

class Airplane extends Vehicle {

var $wingspan = 200; 

}

$a_class = "Airplane";

$attribs = get_class_vars($a_class);

// $attribs = array ("model" => "",

// "current_speed" => "",

// "wingspan" => "200");

?> 


get_object_vars( ).


Функция get_object_vars( ) возвращает ассоциативный массив с информацией обо всех атрибутах объекта с заданным именем. Синтаксис функции get_object_vars( ): 

array get_object_vars (object имя_обьекта) 

Пример использования функции get_object_vars( ) приведен в листинге 9. 


Листинг 9. Получение информации о переменных объекта. 


class Vehicle {

var $wheels;

}

class Land extends Vehicle {

var $engine;

}

class car extends Land {

var $doors;

function car($doors, $eng, $wheels) {

$this->doors = $doors;

$this->engine = $eng;

$this->wheels = $wheels;

}

function get_wheels() {

return $this->wheels;

}

}

$toyota = new car(2,400,4);

$vars = get_object_vars($toyota);

while (list($key, $value) = each($vars)) :

print "$key ==> $value 
";

endwhile;

// Выходные данные:

// wheels ==> 2

// engine ==> 400

// doors ==> 2

?> 


Функция get_object_vars( ) позволяет быстро получить всю информацию об атрибутах конкретного объекта и их значениях в виде ассоциативного массива. 


method_exists( ).


Функция method_exists( ) проверяет, поддерживается ли объектом метод с заданным именем. Если метод поддерживается, функция возвращает TRUE, в противном случае возвращается FALSE. Синтаксис функции method_exists( ): 

bool method_exists (object имя_обьекта. string имя_метода) 

Пример использования метода method_exists( ) приведён в листинге 10. 


Листинг 10. Проверка поддержки метода объектом при помощи функции method_exists(). 


class Vehicle {

//...

}

class Land extends Vehicle {

var $fourWheel;

function setFourWheelDrive() {

$this->fourWeel = 1;

}

}

// Создать объект с именем $саr

$car = new Land;

// Если метод "fourWheelDrive" поддерживается классом "Land"

// или "Vehicle", вызов method_exists возвращает TRUE;

// в противном случае возвращается FALSE.

// В данном примере method_exists() возвращает TRUE.

if (method_exists($car, "setfourWheelDrive")) :

print "This car is equipped with 4-wheel drive";

else :

print "This car is not equipped with 4-wheel drive";

endif;

?> 


В листинге 10 функция method_exists ( ) проверяет, поддерживается ли объектом $car метод с именем setFourWheelDrive( ). Если метод поддерживается, функция возвращает логическую истину и фрагмент выводит соответствующее сообщение. В противном случае возвращается FALSE и выводится другое сообщение. 


get_class( ).


Функция get_class( ) возвращает имя класса, к которому относится объект с заданным именем. Синтаксис функции get_class( ): 

string get_class(object имя_объекта); 

Пример использования get_class( ) приведен в листинге 11. 


Листинг 11. Получение имени класса функцией get_class( ). 


class Vehicle {

//...

}

class Land extends Vehicle {

//...

}

// Создать объект с именем $саr 

$car = new Land;

// Переменной $class_a присваивается строка "Land"

$class_a = get_class($car);

?> 


В результате переменной $class_a присваивается имя класса, на основе которого был создан объект $саr. 


get_parent_class( ).


Функция get_parent_class( ) возвращает имя родительского класса (если он есть) для объекта с заданным именем. Синтаксис функции get_parent_dass( ): 

string get_parent_class (object имя_обьекта); 

Листинг 12 демонстрирует использование get_parent_class( ). 


Листинг 12. Получение имени родительского класса функцией get_parent_class( ). 


class Vehicle {

//...

}

class Land extends Vehicle {

//...

}

// Создать объект с именем $саr 

$car = new Land;

// Переменной $parent присваивается строка "Vehicle"

$parent = get_parent_class($car);

?> 


Как и следовало ожидать, при вызове get_parent_class( ) переменной $parent будет присвоена строка "Vehicle". 


is_subclass_of( ).


Функция is_subclass_of( ) проверяет, был ли объект создан на базе класса, имеющего родительский класс с заданным именем. Функция возвращает TRUE, если проверка дает положительный результат, и FALSE в противном случае. Синтаксис функции is_subclass_of( ): 


bool is_subclass_of (object объект, string имя_класса) 

Использование is_subclass_of( ) продемонстрировано в листинге 13. 


Листинг 13. Использование функции is_subdass_of( ). 


class Vehicle {

//...

}

class Land extends Vehicle {

//...

}

$auto = new Land;

// Переменной $is_subclass присваивается TRUE

$is_subclass = is_subclass_of($auto, "Vehicle");

?> 


В листинге 13 переменной $is_subclass( ) присваивается признак того, принадлежит ли объект $auto к субклассу родительского класса Vehicle. В приведенном фрагменте $auto относится к классу Vehicle; следовательно, переменной $is_subclass( ) будет присвоено значение TRUE. 


get_declared_classes( ).


Функция get_declared_classes( ) возвращает массив с именами всех определенных классов (листинг 14). Синтаксис функции get_declared_classes( ): 

array get_declared_classes( ) 


Листинг 14. Получение списка классов функцией get_declared_classes( ). 


class Vehicle {

//...

}

class Land extends Vehicle {

//...

}

$declared_classes = get_declared_classes();

// $declared_classes = array("Vehicle", "Land")

}

?> 

Задания




  1.  
    Создать класс, описывающий web-страницу. Класс содержит функции, отображающие различные ее части. Создать производные от этого класса классы, описывающие различные модификации страницы. Написать скрипт, выводящий страницы с помощью свойств и методов этих классов.
  2.  
    Создать класс, содержащий функции для работы с текстовым файлом (создание файла, удаление файла). Написать скрипт, использующий функции этого класса.
  3.  
    Создать класс, содержащий функции для выполнения арифметических действий (сложение, вычитание, умножение и деление) над двумя числами. Написать скрипт, использующий эти функции.
  4.  
    Создать класс, содержащий функции работы со строкой (определение длины строки; n-го символа строки; букв, входящих в строку более одного раза) . Написать скрипт, использующий эти функции.
  5.  
    Создать класс, содержащий следующие функции для функционирования гостевой книги: добавить сообщение, вывести все сообщения, проверить наличие пустых полей. Написать скрипт, использующий эти функции.


 

А также другие работы, которые могут Вас заинтересовать

12350. Әлеуметтану – ғылыми пән. Әлеуметтанудың құрылымы мен функциялары 64.5 KB
  1 дәріс. Әлеуметтану – ғылыми пән 1. Қоғам және әлеумет ұғымдарының мәні. 2. Әлеуметтанудың объектісі мен пәні. 3. Әлеуметтанудың категориялары мен заңдары. 4. Әлеуметтанудың құрылымы мен функциялары.
12351. Әлеуметтану ғылыми пән ретінде. Әлеуметтанудың құрылымы мен функциялары 58 KB
  Әлеуметтану ғылыми пән ретінде 1. Қоғам және әлеумет ұғымдарының мәні. 2. Әлеуметтанудың объектісі мен пәні. 3. Әлеуметтанудың категориялары мен заңдары. 4. Әлеуметтанудың құрылымы мен функциялары. 5. Әле
12352. Исследование затухающих колебаний в колебательном контуре 458 KB
  Лабораторная работа № 25 Исследование затухающих колебаний в колебательном контуре 1. Цель работы: Изучение параметров и характеристик реального колебательного контура. 2. Затухающие колебания. Если диссипативную систему находящуюся в колебательном движении пр...
12353. Изучение электрических колебаний в связанных контурах 252 KB
  Лабораторная работа № 24 Изучение электрических колебаний в связанных контурах 1. Цель работы: Изучение обмена энергии в системе электрических контуров слабо связанных между собой. 2. Колебательные системы со слабой связью. Рассмотрим систему двух одинаковых мая
12354. Изучение свойств p-n перехода 283 KB
  Лабораторная работа № 23 Изучение свойств pn перехода 1. Цель работы: изучение вольтамперных характеристик при прямом и обратном направлении протекающего через переход тока и вольтфарадной зависимость емкости перехода от приложенного напряжения характеристики pn...
12355. Изучение вынужденных колебаний в колебательном контуре 343.5 KB
  Лабораторная работа № 22 Изучение вынужденных колебаний в колебательном контуре 1. Цель работы: изучение зависимости тока в колебательном контуре от частоты источника включенного в контур измерение резонансной частоты контура. 2. Вынужденные колебания в RLCконтур
12356. Скин-эффект в металле 182.5 KB
  Лабораторная работа № 21 Скинэффект в металле 1. Цель работы: Изучение скинэффекта в металле. 2. Электромагнитная индукция. Вихревое электрическое поле. Явление электромагнитной индукции состоит в том что в проводящем контуре находящемся в переменном магнитном
12357. Изучение магнитного поля соленоида с помощью датчика Холла 198.5 KB
  Лабораторная работа № 20 Изучение магнитного поля соленоида с помощью датчика Холла 1. Цель работы: исследование магнитного поля на оси соленоида с использованием датчика Холла. 2. Методика измерений. Сначала получим выражение для расчета индукции магнитного пол
12358. Определение отношения заряда электрона к его массе методом магнетрона 245 KB
  Лабораторная работа № 19 Определение отношения заряда электрона к его массе методом магнетрона 1. Цель работы: измерение удельного заряда |e|/m электрона. 2. Методика измерений Существуют различные методы определения отношения |e|/m в основе которых лежат результа...