Skip to content

Instantly share code, notes, and snippets.

@helloanoop
Last active January 1, 2019 18:34
Show Gist options
  • Save helloanoop/c94e214290a63e0a479b67a1fbbffda6 to your computer and use it in GitHub Desktop.
Save helloanoop/c94e214290a63e0a479b67a1fbbffda6 to your computer and use it in GitHub Desktop.

Revisions

  1. helloanoop revised this gist Jan 1, 2019. No changes.
  2. helloanoop created this gist Jan 1, 2019.
    139 changes: 139 additions & 0 deletions database.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,139 @@
    <?php

    class Database
    {
    /**
    * Storage
    * @var array
    */
    protected $database = array();

    /**
    * Transactions
    * @var array
    */
    protected $transactions = array();

    /**
    * Value usage counter
    * @var array
    */
    protected $valueUsage = array();

    /**
    * Set value
    * @param $name
    * @param bool $value
    */
    protected function setValue($name,$value=false)
    {
    if(isset($this->database[$name])) {
    $this->valueUsage[$this->database[$name]] -= 1;
    unset($this->database[$name]);
    }

    if ($value) {
    $this->database[$name] = $value;
    // IDEA: if values are mostly large, we can keep their hashes as $valueUsage key
    $this->valueUsage[$value] = isset($this->valueUsage[$value]) ? $this->valueUsage[$value] + 1 : 1;
    }
    }

    /**
    * Keep records about value change
    * @param $name
    */
    protected function addTransactionChange($name)
    {
    if ($this->transactions) {
    $lastTransaction = end($this->transactions);
    if (!isset($lastTransaction[$name])) {
    $this->transactions[key($this->transactions)][$name] = $this->get($name);
    }
    }
    }

    /**
    * Open a transactional block
    */
    public function begin()
    {
    array_push($this->transactions, array());
    }

    /**
    * Rollback all of the commands from the most recent transaction block
    *
    * @throws Exception
    */
    public function rollback()
    {
    if ($this->transactions) {
    $lastTransaction = end($this->transactions);
    foreach($lastTransaction as $name => $value) {
    $this->setValue($name,$value);
    }
    unset($this->transactions[key($this->transactions)]);
    } else {
    throw new Exception("INVALID ROLLBACK");
    }
    }

    /**
    * Permanently store all of the operations from any presently open transactional blocks
    */
    public function commit()
    {
    $this->transactions = array();
    }

    /**
    * Return the value stored under the variable $name
    * @param $name
    * @return string
    */
    public function get($name)
    {
    return isset($this->database[$name]) ? $this->database[$name] : 'null';
    }

    /**
    * Set variable
    * @param $name
    * @param $value
    */
    public function set($name,$value)
    {
    $this->addTransactionChange($name);
    $this->setValue($name,$value);
    }

    /**
    * Unset variable
    * @param $name
    */
    public function delete($name)
    {
    $this->addTransactionChange($name);
    $this->setValue($name);
    }

    /**
    * Returns the number of variables equal to $value
    * @param $value
    * @return int
    */
    public function numEqualTo($value)
    {
    return isset($this->valueUsage[$value]) ? $this->valueUsage[$value] : 0;
    }
    }
    55 changes: 55 additions & 0 deletions index.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,55 @@
    <?php

    require_once('database.php');

    $database = new Database();
    if(!defined('STDIN')) define('STDIN', fopen('php://stdin', 'r'));
    if(!defined('STDOUT')) define('STDOUT', fopen('php://stdout', 'w'));
    if(!defined('STDERR')) define('STDERR', fopen('php://stderr', 'w'));
    fwrite(STDOUT, "\nHey! Program will terminate on command 'END'\n\n");

    $data = array();

    do {
    $command = trim(fgets(STDIN));
    $data[] = explode(' ', $command);
    } while ($command != 'END');

    fwrite(STDOUT, "-- OUTPUT --\n");

    try {
    foreach ($data as $cmd) {
    switch ($cmd[0]) {
    case 'BEGIN':
    $database->begin();
    break;
    case 'ROLLBACK':
    $database->rollback();
    break;
    case 'COMMIT':
    $database->commit();
    break;
    case 'GET':
    echo $database->get($cmd[1])."\n";
    break;
    case 'SET':
    $database->set($cmd[1],@$cmd[2]);
    break;
    case 'UNSET':
    $database->delete($cmd[1]);
    break;
    case 'NUMEQUALTO':
    echo $database->numEqualTo($cmd[1])."\n";
    break;
    case 'END':
    exit(0);
    break;
    default:
    fwrite(STDOUT, "There is no command $cmd[0]!\n");
    exit(0);
    break;
    }
    }
    } catch(Exception $e) {
    fwrite(STDOUT, $e->getMessage());
    }