ООП   PHP   web   4GL - визуальные среды

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

  1. Новая объектно-ориентированная модель в PHP5
  2. Новый объектно-ориентированный подход в PHP5
  3. public/private/protected - модификаторы доступа для методов и свойств
  4. Унифицированный конструктор __construct()
  5. Поддержка деструктора для класса, определяемого как метод __destructor()
  6. Явное клонирование объекта
  7. Константы класса
  8. Статические члены класса
  9. Статические методы
  10. Абстрактные классы
  11. Абстрактные методы
  12. Указание класса как типа
  13. Поддержка разыменования объектов, которые возвращаются методами
  14. Итераторы
  15. __autoload()
  16. Обработка исключительных ситуаций (исключений)
  17. Перегрузка методов
  18. Перегрузка свойств классов
  19. Оператор instanceof
  20. Метод final
  21. Классы, помеченные как final

Новая объектно-ориентированная модель в PHP5

Когда Зив Сераски (Zeev Suraski) добавил объектно-ориентированный (ОО) синтаксис в PHP 3, это можно было рассматривать как "синтаксический подсластитель для поддержки классов" ("syntactic sugar for accessing collections"). Объектно-ориентированная модель получила поддержку наследования и позволяла классу (и объекту) объединять методы и свойства, но не более того. Когда Зив и Анди переписали движок для PHP 4, это был полностью новый движок, работающий намного быстрее, намного стабильнее и с еще многими другими возможностями. Однако, изменения практически не затронули ОО модель, первоначально введенную еще в РНР 3.

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

Какие были ограничения в PHP 3 и 4? Самым большим ограничением (которое и приводило ко всем остальным ограничениям) был тот факт, что семантика экземпляра объекта была такой же, что и для родных типов. Как это фактически отражалось на разработчиках? Когда вы присваивали переменную (которая указывает на объект) другой переменной, то создавалась копия объекта. Мало того, что это влияло на производительность, но и это обычно приводило к ошибкам в приложении, потому что многие разработчики думали, что обе переменные будут указывать на тот же самый объект. А они указывали на разные копии того же самого объекта, поэтому, изменяя один объект, мы не меняли другой. Вот пример:

<?php
class Person {
var
$name;
function
getName() {
return
$this->name;
}
function
setName($name) {
$this->name = $name;
}
function
Person($name) {
$this->setName($name);
}
}

function
changeName($person, $name) {
$person->setName($name);
}

$person = new Person("Andi");
changeName($person, "Stig");
print
$person->getName();
?>

В РНР 4 этот код выведет "Andi". Причина кроется в том, что мы передаем объект $person в функцию changeName() по значению, а не по ссылке, таким образом, объект $person будет скопирован, и changeName() будет работать уже с копией объекта $person.

Такое поведение не является интуитивно понятным. Действительно, многие разработчики ожидали Java-подобного поведения. В Java, переменные фактически являются указателями на объект, и поэтому при дублировании будет скопирован указатель, а не сам объект.

Было два вида разработчиков: те, кто знал об этой проблеме, и те, кто не знал. Последние, обычно, не сталкивались с этой проблемой, потому что их код был написан так, что было безразлично, существует ли такая проблема или нет. Конечно, некоторые из этих разработчиков проводили бессонные ночи в "увлекательных" поисках "сверхъестественных" ошибок. Первая группа также имела проблему, поскольку приходилось вручную определять передачу объекта по ссылке, запрещая движку копировать объекты, и код был испещрен многочисленными знаками '&'.

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

В PHP 5 объектная модель была полностью переписана для того, чтобы сразу работать с указателями на объект. Если вы явно не клонируете объект, используя ключевое слово clone, вы никогда не будете работать с копией объекта, думая, что работаете с самим объектом. В PHP 5 уже не нужно явно передавать объекты или присваивать их по ссылке, это делается автоматически.

Обратите внимание: явная передача и присваивание по ссылке также поддерживается, на тот случай, если вы хотите изменить содержимое переменной или объекта.

Новый объектно-ориентированный подход в PHP5

Новые возможности объектной модели являются слишком многочисленными. Приведем обзор главных изменений:

public/private/protected - модификаторы доступа для методов и свойств

Позволяют управлять доступом к методам и свойствам. Теперь видимость свойств и методов может быть определена ключевыми словами: public, private, protected. Модификатор public позволяет обращаться к свойствам и методам отовсюду. Модификатор private позволяет обращаться к свойствам и методам только внутри текущего класса. Модификатор protected позволяет обращаться к свойствам и методам только текущего класса и класса, который наследует свойства и методы текущего класса.

<?php
/**
* Define MyClass
*/
class MyClass
{
public
$public = 'Public';
protected
$protected = 'Protected';
private
$private = 'Private';

function
printHello()
{
echo
$this->public;
echo
$this->protected;
echo
$this->private;
}
}

$obj = new MyClass();
echo
$obj->public; // Works
echo $obj->protected; // Fatal Error
echo $obj->private; // Fatal Error
$obj->printHello(); // Shows Public, Protected and Private


/**
* Define MyClass2
*/
class MyClass2 extends MyClass
{
// We can redeclare the public and protected method, but not private
protected $protected = 'Protected2';

function
printHello()
{
echo
$this->public;
echo
$this->protected;
echo
$this->private;
}
}

$obj2 = new MyClass2();
echo
$obj->public; // Works
echo $obj2->private; // Undefined
echo $obj2->protected; // Fatal Error
$obj2->printHello(); // Shows Public, Protected2, not Private

?>

Унифицированный конструктор __construct()

PHP 5 позволяет объявлять методы-конструкторы. Классы, в которых объявлен метод-констуктор, будут вызывать этот метод при каждом создании нового объекта, так что это может оказаться полезным, чтобы, например, инициализировать какое-либо состояние объекта перед его использованием. Конструктор, ранее совпадавший с названием класса, теперь необходимо объявлять как __construct(), что позволит легче перемещать классы в иерархиях. Конструкторы в классах-родителях не вызываются автоматически. Чтобы вызвать конструктор, объявленный в родительском классе, следует обратиться к методу parent::__construct().

<?php
class BaseClass {
function
__construct() {
print
"Конструктор класса BaseClass\n'';
}
}

class
SubClass extends BaseClass {
function
__construct() {
parent::__construct();
print
"Конструктор класса SubClass\n'';
}
}

$obj = new BaseClass();
$obj = new SubClass();
?>

Если PHP 5 не может обнаружить объявленный метод __construct(), вызов конструктора произойдет по прежней схеме, через обращение к методу, имя которого соответствует имени класса. Может возникнуть только одна проблема совместимости старого кода, если в нём присутствуют классы с методами __construct().

Поддержка деструктора для класса, определяемого как метод __destructor()

PHP 5 предоставляет концепцию деструкторов, сходную с теми, что применяются в других ОО языках, таких, как Java: когда освобождается последняя ссылка на объект, перед высвобождением памяти, занимаемой этим объектом, вызывается метод __destruct(), не принимающий параметров.

<?php
class MyDestructableClass {
function
__construct() {
print
"Конструктор\n'';
$this->name = "MyDestructableClass";
}

function
__destruct() {
print
"Уничтожается''. $this->name . "\n";
}
}

$obj = new MyDestructableClass();
?>

Как и в случае с конструкторами, деструкторы, объявленные в родительском классе, не будут вызваны автоматически. Для вызова деструктора, объявленном в классе-родителе, следует обратиться к методу parent::__destruct().

Явное клонирование объекта

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

Копия объекта создается с использованием вызова clone (который вызывает метод __clone() объекта, если это возможно). Вы можете объявить метод __clone(), который будет вызван при клонировании объекта (после того, как все свойства будут скопированы из исходного объекта).

copy_of_object = clone $object;

Когда программист запрашивает создание копии объекта, PHP 5 определит, был ли для этого объекта объявлен метод __clone() или нет. Если нет, будет вызван метод __clone(), объявленный по умолчанию, который скопирует все свойства объекта. Если метод __clone() был объявлен, создание копий свойств в копии объекта полностью возлагается на него. Для удобства, движок обеспечивает программиста функцией, которая импортирует все свойства из объекта-источника, так что программист может осуществить позначное копирование свойств и переопределять только необходимые. Приведем пример клонирования объекта:

<?php
class MyClass {
function
__clone() {
print
"Объект был клонирован ";
}
}
$obj = new MyClass();
clone
$obj;
?>

Константы класса

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

<?php
class MyClass {
const
SUCCESS = "Success";
const
FAILURE = "Failure";
}
print
MyClass::SUCCESS;
?>

Статические члены класса

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

<?php
class Singleton {
static private
$instance = NULL;

private function
__construct() {
}

static public function
getInstance() {
if (
self::$instance == NULL) {
self::$instance = new Singleton();
}
return
self::$instance;
}
}
?>

Статические методы

Вы можете теперь определить методы как статические, разрешая им быть вызванными вне контекста объекта. Статические методы не определяются через переменную $this, поскольку они не должны быть ограничены определенным объектом.

<?php
class MyClass {
static function
helloWorld() {
print
"Hello, world";
}
}
MyClass::helloWorld();
?>

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

PHP 5 поддерживает определение абстрактных классов и методов. Создавать экземпляр класса, который был объявлен абстрактным, нельзя. Класс, в котором объявлен хотя бы один абстрактный метод, должен также быть объявлен абстрактным. Методы, объявленные как абстрактные, несут, по существу, лишь описательный смысл и не могут включать какой-либо функционал. Класс может быть объявлен как абстрактный при помощи использования ключевого слова abstract, для исключения из обработки движком описания класса. Однако, вы можете наследовать абстрактные классы. Практический пример:

<?php

abstract class AbstractClass {

/* Данный метод должен быть определён в дочернем классе */
abstract protected function getValue();

/* Общий метод */
public function print() {
print
$this->getValue();
}

}

class
ConcreteClass1 extends AbstractClass {

protected function
getValue() {
return
"ConcreteClass1'';
}

}

class
ConcreteClass2 extends AbstractClass {

protected function
getValue() {
return
"ConcreteClass2'';
}

}

$class1 = new ConcreteClass1;
$class1->print();

$class2 = new ConcreteClass2;
$class2->print();
?>

Абстрактные методы

Метод может быть объявлен как abstract, таким образом отложив его определение наследуемым классом. Класс, который включает абстрактные методы, должен быть объявлен как abstract.

<?php
abstract class MyBaseClass {
abstract function
display();
}
?>

Указание класса как типа

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

<?php
function expectsMyClass(MyClass $obj) {

}
?>

Поддержка разыменования объектов, которые возвращаются методами

В PHP 4 вы не могли непосредственно разыменовывать объекты, которые возвращаются из методов. Вы должны были бы сначала присвоить такой объект некой фиктивной переменной.

Поясним на примере. В PHP 4:

<?php
$dummy
= $obj->method();
$dummy->method2();
?>

В PHP 5:

<?php
$obj
->method()->method2();
?>

Итераторы

PHP 5 предоставляет механизм итераторов для получения списка всех свойств какого-либо объекта, например, для использования совместно с оператором foreach. По умолчанию, в итерации будут участвовать все свойства, объявленные как public. Пример использования итераторов:

<?php

class MyClass {
public
$var1 = 'value 1';
public
$var2 = 'value 2';
public
$var3 = 'value 3';

protected
$protected = 'protected';
private
$private = 'private';

}

$class = new MyClass();

foreach(
$class as $key => $value) {
print
"$key => $value\n'';
}

Результат:

var1 => value 1
var2 => value 2
var3 => value 3

Как показывает результат, foreach проитерировал все принадлежащие объекту public-свойства.

__autoload()

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

В PHP 5 в этом больше нет необходимости. Вы можете определить функцию __autoload() , которая автоматически будет вызываться в случае использования класса, который не был определен выше. Вызывая такую функцию, Zend Engine дает возможность загрузить файл с определением класса прежде, чем будет сформировано сообщение об ошибке и выполнение скрипта прекратится.

<?php
function __autoload($class_name) {
include_once(
$class_name . "php");
}

$obj = new MyClass1();
$obj2 = new MyClass2();
?>

Обработка исключительных ситуаций (исключений)

PHP 5 добавляет парадигму обработки исключений, вводя структуру try/throw/catch. Вам остается только создать объекты, которые наследуют класс исключений Exception.

<?php
class SQLException extends Exception {
public
$problem;
function
__construct($problem) {
$this->problem = $problem;
}
}

try {
...
throw new
SQLException("Couldn't connect to database");
...
} catch (
SQLException $e) {
print
"Caught an SQLException with problem $obj->problem'';
} catch (
Exception $e) {
print
"Caught unrecognized exception";
}
?>

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

Сравнение объектов

В PHP 5 сравнение объектов является более сложным процессом, чем в PHP 4, а также процессом, более соответствующим идеологии объектно-ориентированного языка.

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

С другой стороны, при использовании оператора идентичности (===), свойства объекта считаются идентичными тогда и только тогда, когда они ссылаются на один и тот же экземпляр одного и того же класса.

Следующий пример внесёт ясность.

<?php
function bool2str($bool) {
if (
$bool === false) {
return
'FALSE';
} else {
return
'TRUE';
}
}

function
compareObjects(&$o1, &$o2) {
echo
'o1 == o2 : '.bool2str($o1 == $o2)."\n";
echo
'o1 != o2 : '.bool2str($o1 != $o2)."\n";
echo
'o1 === o2 : '.bool2str($o1 === $o2)."\n";
echo
'o1 !== o2 : '.bool2str($o1 !== $o2)."\n";
}

class
Flag {
var
$flag;

function
Flag($flag=true) {
$this->flag = $flag;
}
}

class
OtherFlag {
var
$flag;

function
OtherFlag($flag=true) {
$this->flag = $flag;
}
}

$o = new Flag();
$p = new Flag();
$q = $o;
$r = new OtherFlag();

echo
"Два экземпляра одного и того же класса\n";
compareObjects($o, $p);

echo
"\nДве ссылки на один и тот же экземпляр\n";
compareObjects($o, $q);

echo
"\nЭкземпляры двух разных классов\n";
compareObjects($o, $r);
?>

Результатом выполнения этого кода будет:

Два экземпляра одного и того же класса
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : FALSE
o1 !== o2 : TRUE

Две ссылки на один и тот же экземпляр
o1 == o2 : TRUE
o1 != o2 : FALSE
o1 === o2 : TRUE
o1 !== o2 : FALSE

Экземпляры двух разных классов
o1 == o2 : FALSE
o1 != o2 : TRUE
o1 === o2 : FALSE
o1 !== o2 : TRUE

Перегрузка свойств классов

Обращения к свойствам объекта могут быть перегружены с использованием методов __call, __get и __set. Эти методы будут срабатывать только в том случае, если объект или наследуемый объект не содержат свойства, к которому осуществляется доступ. Синтаксис такой:

void __set ( string имя, mixed значение )

void __get ( mixed имя )

С помощью этих методов обращения к свойствам класса могут быть перегружены с целью выполнения произвольного кода, описанного в классе. В аргументе имя передаётся имя свойства, к которому производится обращение. Аргумент значение метода __set() должен содержать значение, которое будет присвоено свойству класса с именем имя.

Пример перегрузки с использованием __get и __set:

<?php
class Setter {
public
$n;
private
$x = array("a" => 1, "b" => 2, "c" => 3);

function
__get($nm) {
print
"Читаем [$nm]\n'';

if (isset(
$this->x[$nm])) {
$r = $this->x[$nm];
print
"Получили: $r\n";
return
$r;
} else {
print
"Ничего!\n";
}
}

function
__set($nm, $val) {
print
"Пишем $val в [$nm]\n";

if (isset(
$this->x[$nm])) {
$this->x[$nm] = $val;
print
"OK!\n";
} else {
print
"Всё плохо!\n";
}
}
}

$foo = new Setter();
$foo->n = 1;
$foo->a = 100;
$foo->a++;
$foo->z++;
var_dump($foo);
?>

Результатом выполнения рассмотренного скрипта будет:

Пишем 100 в [a]
OK!
Читаем [a]
Получили: 100
Пишем 101 в [a]
OK!
Читаем [z]
Ничего!
Пишем 1 в [z]
Всё плохо!
object(Setter)#1 (2) {
["n"]=>
int(1)
["x:private"]=>
array(3) {
["a"]=>
int(101)
["b"]=>
int(2)
["c"]=>
int(3)
}
}

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

Вызовы методов могут быть перегружены с использованием методов __call, __get и __set. Эти методы будут срабатывать только в том случае, если объект или наследуемый объект не содержат метода, к которому осуществляется доступ. Синтаксис:

mixed __call ( string имя, array аргументы )

С использованием этого метода, методы класса могут быть перегружены с целью выполнения произвольного кода, описанного в классе. В аргументе имя передаётся имя вызванного метода. Аргументы, которые были переданы методу при обращении, будут возвращены чере аргументы. Значение, возвращённое методом __call(), будет передано вызывающему оператору.

Пример перегрузки с использованием __call:

<?php
class Caller {
private
$x = array(1, 2, 3);

function
__call($m, $a) {
print
"Вызван метод $m :\n";
var_dump($a);
return
$this->x;
}
}

$foo = new Caller();
$a = $foo->test(1, "2", 3.4, true);
var_dump($a);
?>

Результат выполнения рассмотренного примера:

Вызван метод test:
array(4) {
[0]=>
int(1)
[1]=>
string(1) "2"
[2]=>
float(3.4)
[3]=>
bool(true)
}
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}

Интерфейсы

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

Интерфейсы объявляются так же, как и обычные классы, но с использованием ключевого слова "interface"; тела методов интерфейсов должны быть пустыми. Для включения интерфейса в класс программист должен использовать ключевое слово "implements" и описать функционал методов, перечисленных во включаемом интерфейсе. Если это требуется, классы могут включать более одного интерфейса путём их перечисления через пробел.

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

<?php
interface ITemplate
{
public function
setVariable($name, $var);
public function
getHtml($template);
}

class
Template implements ITemplate
{
private
$vars = array();

public function
setVariable($name, $var)
{
$this->vars[$name] = $var;
}

public function
getHtml($template)
{
foreach(
$this->vars as $name => $value) {
$template = str_replace('{'.$name.'}', $value, $template);
}

return
$template;
}
}
?>

Оператор instanceof

Поддержка проверки зависимости от других объектов. Функцией is_a(), известной из PHP 4, пользоваться теперь не рекомендуется.

<?php
if ($obj instance of Circle) {
print
'$obj is a Circle';
}
?>

Метод final

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

<?php
class BaseClass {
public function
test() {
echo
"Вызван метод BaseClass::test()\n";
}

final public function
moreTesting() {
echo
"Вызван метод BaseClass::moreTesting()\n";
}
}

class
ChildClass extends BaseClass {
public function
moreTesting() {
echo
"Вызван метод ChildClass::moreTesting()\n";
}
}
// Выполнение заканчивается фатальной ошибкой:
//Cannot override final method BaseClass::moreTesting()
// (Метод BaseClass::moretesting() не может быть переопределён)
?>

Классы, помеченные как final

После объявления класса final он не может быть унаследован. Следующий пример вызовет ошибку:

<?php
final class FinalClass {
}

class
BogusClass extends FinalClass {
}
?>

Более подробно о возможностях PHP5 и Zend 2.0 вы можете узнать, обратившись к документации Zend Engine 2.0.

ООП   PHP   web   4GL - визуальные среды

Знаете ли Вы, что в 1965 году два американца Пензиас (эмигрант из Германии) и Вильсон заявили, что они открыли излучение космоса. Через несколько лет им дали Нобелевскую премию, как-будто никто не знал работ Э. Регенера, измерившего температуру космического пространства с помощью запуска болометра в стратосферу в 1933 г.? Подробнее читайте в FAQ по эфирной физике.

НОВОСТИ ФОРУМАФорум Рыцари теории эфира
Рыцари теории эфира
 07.07.2020 - 04:30: ЭКОНОМИКА И ФИНАНСЫ - Economy and Finances -> ПРОБЛЕМА КРИМИНАЛИЗАЦИИ ЭКОНОМИКИ - Карим_Хайдаров.
07.07.2020 - 04:24: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от Владимира Николаевича Боглаева - Карим_Хайдаров.
07.07.2020 - 04:00: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от Андрея Маклакова - Карим_Хайдаров.
06.07.2020 - 14:05: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от Михаила Делягина - Карим_Хайдаров.
06.07.2020 - 11:47: ПЕРСОНАЛИИ - Personalias -> WHO IS WHO - КТО ЕСТЬ КТО - Карим_Хайдаров.
06.07.2020 - 08:46: СОВЕСТЬ - Conscience -> РУССКИЙ МИР - Карим_Хайдаров.
06.07.2020 - 04:18: ВОЙНА, ПОЛИТИКА И НАУКА - War, Politics and Science -> Проблема государственного терроризма - Карим_Хайдаров.
06.07.2020 - 04:14: ВОЙНА, ПОЛИТИКА И НАУКА - War, Politics and Science -> РАСЧЕЛОВЕЧИВАНИЕ ЧЕЛОВЕКА. КОМУ ЭТО НАДО? - Карим_Хайдаров.
05.07.2020 - 18:02: ВОЙНА, ПОЛИТИКА И НАУКА - War, Politics and Science -> ПРОБЛЕМЫ КОНСПИРОЛОГИИ - ГЕРМЕТИЗАЦИИ ЗНАНИЙ - Карим_Хайдаров.
05.07.2020 - 18:01: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Проблема народного образования - Карим_Хайдаров.
05.07.2020 - 17:52: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от Игоря Стрелкова - Карим_Хайдаров.
05.07.2020 - 12:30: ЭКОЛОГИЯ - Ecology -> Биологическая безопасность населения - Карим_Хайдаров.
Bourabai Research Institution home page

Bourabai Research - Технологии XXI века Bourabai Research Institution