Проблемы с безопасностью доступа
Почему у нас есть доступ к системе безопасности? Традиционно в средах PHP немногие пользователи Phper сталкиваются с так называемыми проблемами доступа с переменной безопасностью. Например, код примерно выглядит следующим образом:
class db
{
protected static $instance;
protected $dbCon;
function __construct()
{
/*
* Here we use stdClass to simulate a database connection
*/
$this->dbCon = new \stdClass();
}
public static function getInstance()
{
if(!isset(self::$instance)){
self::$instance = new db();
}
return self::$instance;
}
function dbCon()
{
return $this->dbCon;
}
}
$con = db::getInstance()->dbCon();
$con->key = 'new';
var_dump($con->key);Это очень распространенное использование одноэлементного режима подключения к базе данных в режиме FPM. На первый взгляд, никаких проблем, но на самом деле в контексте совместной работы возникнут проблемы с использованием соединений для совместной работы, например, следующие
go(function (){
go(function (){
db::getInstance()->dbCon()->key = 'one';
// Suppose that this SQL executes for 1s
\co::sleep(1);
var_dump(db::getInstance()->dbCon()->key);
});
go(function (){
db::getInstance()->dbCon()->key = 'two';
// Suppose this SQL executes 0.1s
\co::sleep(0.1);
var_dump(db::getInstance()->dbCon()->key);
});
});Мы обнаружим, что в приведенном выше коде данные совместного выполнения 2 загрязняют данные совместного выполнения 1, поэтому это, безусловно, невозможно.
Контекстный менеджер
Чтобы решить эту проблему, мы вводим концепцию управления контекстом совместной работы для обеспечения изоляции данных в каждой среде совместной работы.
class dbContext
{
private $container = [];
private static $instance;
public static function getInstance()
{
if(!isset(self::$instance)){
self::$instance = new dbContext();
}
return self::$instance;
}
function dbCon()
{
$cid = \co::getCid();
if(!isset($this->container[$cid])){
$this->container[$cid] = new stdClass();
defer(function (){
$this->destroy();
});
}
return $this->container[$cid];
}
function destroy()
{
$cid = \co::getCid();
if(!isset($this->container[$cid])){
unset($this->container[$cid]);
}
}
}
go(function (){
go(function (){
dbContext::getInstance()->dbCon()->key = 'one';
// Suppose that this SQL executes for 1s
\co::sleep(1);
var_dump(dbContext::getInstance()->dbCon()->key);
});
go(function (){
dbContext::getInstance()->dbCon()->key = 'two';
// Suppose this SQL executes 0.1s
\co::sleep(0.1);
var_dump(dbContext::getInstance()->dbCon()->key);
});
});В приведенном выше коде мы используем идентификатор каждого протокола в качестве маркера данных каждого стека протоколов и используем метод отсрочки для автоматической очистки данных при выходе из каждого протокола, что позволяет избежать утечки памяти.
Универсальная версия управления контекстом пула соединений и совместной работы
Мы легко можем обнаружить, что в приведенном выше коде, на самом деле, это все еще режим управления коротким соединением. Нет возможности повторно использовать ссылки. Поскольку в статье объясняются только основные принципы, студенты, которые заинтересованы в этом, могут проверить пул соединений и следующий менеджер фреймворка Easy swool. Домашняя страница проекта находится на сайте www. easyswool .com. Если вам захочется, вы можете помочь Е. На складе GitHub Asyswool есть несколько комплиментов.