Я работаю над набором компонентов (которые, надеюсь, станут полноценными фреймворками) и сейчас работаю над одним из них, чтобы обеспечить абстракцию PHP-сессий.
Я пытаюсь сделать код как можно более тестируемым, но сессионный класс по определению будет полагаться на глобальное состояние в форме суперглобального $ _SESSION.
Я пытался реализовать мой класс сеанса таким образом, чтобы функции $ SESSION и сеанс * вызывались только в одном месте, которое затем я могу переопределить в PHPUnit для целей тестирования, но я могу Я не думаю, что есть лучший способ сделать это.
Если вы можете предложить лучший подход к созданию тестируемого сеанса, то я был бы признателен за любой вклад, который вы можете иметь.
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
namespace gordian\reefknot\storage\session;
use gordian\reefknot\storage;
/**
* Session management
*
* Each instance of the Session object represents a "namespace" within the PHP
* $_SESSION system. This allows sessions to be easily managed and organized
* within an application
*
*/
class Session implements storage\iface\Crud, iface\Session
{
protected
$name = '',
$storage = NULL;
/**
* Add a new item to the session
*
* @param mixed $data
* @param string $key
* @return Session
* @throws \InvalidArgumentException Thrown if no name is provided
*/
public function createItem ($data, $key)
{
if (!empty ($key))
{
$key = (string) $key;
if (($this -> storage === NULL)
|| (!array_key_exists ($key, $this -> storage)))
{
$this -> storage [$key] = $data;
}
}
else
{
throw new \Exception ('No valid key given');
}
return ($this);
}
/**
* Delete the specified key
*
* @param string $key
* @return Session
*/
public function deleteItem ($key)
{
unset ($this -> storage [$key]);
return ($this);
}
/**
* Retrieve the data stored in the specified key
*
* @param type $key
* @return mixed
*/
public function readItem ($key)
{
return (array_key_exists ($key, $this -> storage)?
$this -> storage ['key']:
NULL);
}
/**
* Update a previously stored data item to a new value
*
* @param mixed $data
* @param string $key
*/
public function updateItem ($data, $key)
{
if ($this -> storage === NULL)
{
throw new \RuntimeException ('Session contains no data');
}
if (array_key_exists ($key, $this -> storage))
{
$this -> storage [$key] = $data;
}
return ($this);
}
/**
* Clear the session of all stored data
*
* @return Session
*/
public function reset ()
{
$this -> storage = NULL;
return ($this);
}
/**
* Retrieve all data stored in the session
*
* @return array
*/
public function getAll ()
{
return ($this -> storage);
}
/**
* Return whether there is data stored in this session
*
* @return bool
*/
public function hasData ()
{
return (!empty ($this -> storage));
}
/**
* Initialize the back-end storage for the session
*
* This method provides access for this class to the underlying PHP session
* mechanism.
*
* @return bool Whether the newly initialized session contains data or not
* @throws \RuntimeException Will be thrown if the session failed to start
*/
protected function initStorage ()
{
// Check that storage hasn't already been initialized
if ($this -> storage === NULL)
{
// Attempt to start the session if it hasn't already been started
if ((session_id () === '')
&& ((headers_sent ())
|| ((!session_start ()))))
{
throw new \RuntimeException ('Unable to start session at this time');
}
// Alias our instance storage to the named $_SESSION variable
$this -> storage =& $_SESSION [$this -> name];
}
return ($this -> hasData ());
}
/**
* Class constructor
*
* @param string $sessName
* @throws \InvalidArgumentException Thrown if no session name is provided
*/
public function __construct ($sessName)
{
if (!empty ($sessName))
{
$this -> name = $sessName;
$this -> initStorage ();
}
else
{
throw new \InvalidArgumentException ('Session must have a name');
}
}
}
Для тестирования текущий план состоит в том, чтобы заменить initStorage () методом, который просто устанавливает внутренний массив. Если вы можете предложить лучший подход, я бы хотел услышать это.