📜 ⬆️ ⬇️

Architecture Notes or Forth Interpreter for PHP 5.3

What will be discussed?


I often have to conduct interviews, hiring PHP-programmers. 2-3 people a day is quite normal, although on the verge of endurance.

All candidates are different, someone is just great, someone is worse. But those who are worse, always have the same mistakes.

First of all, they are not at all interested in the development of the language in which they write, and the question “What's new in PHP 5.3” confuses them, and the suggestion to speculate on the topic “What would you add to future versions of the language?” Just scares.
')
Secondly, they categorically do not represent that PHP can be at least something other than "scripts for sites." This is especially sad in light of the fact that at work they will have to deal with far from sites and even most likely not sites.

Well, in the third candidates who are worse, hardly imagine the process of building the architecture of the program. Patterns - they know, and a lot, but how to put the whole system out of the patterns, so that it is not painfully embarrassing for it - this is already difficult.

Such candidates and is dedicated to this topic. With respect to their difficult part (and being a programmer is actually not easy) and with the hope that he will push them forward along the path of self-improvement.

What do we do?

Let's try to make the Fort interpreter in PHP!

The fort always attracted me, like a distant galaxy from antimatter. The stack, the words in the dictionary, the reverse Polish notation ... It only seems complicated, but actually very simple, but it’s great to “enlighten” and broaden your horizons.

Let's make our application a console, no browsers and servers. Let's write it in PHP 5.3, trying to use the language 100%. And, of course, we try to initially make sure that those who came after us do not hang from our code on the very first day.

Application architecture

From the very beginning, we agreed with you that we are writing in PHP 5.3, and this greatly facilitates the work of the system architect. We will adopt several principles at once which we will adhere to during the development:
  1. We use namespaces to separate application levels.
  2. Each class name must uniquely indicate its place in the file system.
  3. One class - one file
  4. All classes are included only through autoload.
  5. All errors are handled by exceptions, exception classes are subject to general rules.

Take as the root namespace for our application \ FORTH. The main classes of the Fort-machine are set to \ FORTH \ SYSTEM, and the exceptions will be placed in \ FORTH \ EXCEPTIONS, which itself will also be divided into several, for example - \ FORTH \ EXCEPTIONS \ SYSTEM for the exceptions that arise in the Fort system itself, let's say \ FORTH \ EXCEPTIONS \ STACK for exceptions related to the stack.

In accordance with the 2 principle of architecture, we will uniquely convert namespaces to directories in filesystems, and class names to file names in these directories.

It turns out about the following code:

<?php

$autoload = function ($class) {

	$path = explode('\\', $class);

	if ( 'FORTH' != array_shift($path) )
		throw new \FORTH\EXCEPTIONS\SYSTEM\NamespaceIsWrong();

	$filename = array_pop($path);

	require __DIR__ . '/' .
		implode('/', array_map('strtolower', $path)) . '/' . 
		$filename . '.php';

};

spl_autoload_register($autoload);


: ( , ?), SPL, (, , ).

autoload.php .


, -, . — forth.php , forth.bat forth.sh , .

Windows forth.bat :
@echo off
SET PHP_PATH=Z:/usr/local/bin
%PHP_PATH%/php -q ./forth.php %1 > output.txt
type output.txt | more
pause


, sh/csh/bash .

, forth.php, , —
namespace FORTH;
require __DIR__ . '/autoload.php';



-: .

— . , , ().

PHP LIFO array_pop array_push, , . , , . :

<?php

namespace FORTH\SYSTEM;

class Stack extends Singleton {

	private $stack = array();

	public function push($obj) {

		array_push(
			$this->stack,
			$obj
		);

	}

	public function pop() {

		if ( $this->isEmpty() )
			throw new \FORTH\EXCEPTIONS\STACK\StackIsEmpty();
		
		return array_pop(
			$this->stack
		);

	}

	public function isEmpty() {

		return empty($this->stack);

	}

}


, — ? , getInstance()?

— \FORTH\SYSTEM\Singleton. , — LSB, PHP 5.3 .

, array_push array_shift.


. - . ( ) : , ( ), ( ) , , .

\FORTH\SYSTEM\Word, — \FORTH\SYSTEM\Dictionary, .

— , — .

, , - , \FORTH\SYSTEM\Dictionary StandartDictionary, , .

, «DUP» — , «SWAP» — "." — . , :


		/*
		 *    ,    
		 */
		$dict->addWord(
			new Word(
				'+',
				2,
				2,
				function ($a, $b) {
					return (array)($a+$b);
				}
			)
		);



-. , , .

forth.php:
$data = \file_get_contents($argv[1]);

$parser = SYSTEM\Parser::getInstance();
$parser->loadRawData($data);
$dataForQueue = $parser->makeQueue();

$queue = SYSTEM\Queue::getInstance();
$queue->loadArray($dataForQueue);

$stack = SYSTEM\Stack::getInstance();

$executor = SYSTEM\Executor::getInstance();
$executor->setStack($stack);
$executor->execute($queue);


, , , - — , . -, . — -))

«» , — , . , , — , , — -.

«». - — . , .

— , : , , , . , — , , . , , .

:


$args = array();

for ( $i = 1; $i <= $word->getStackPopCount(); $i++ )
	$args[] = $this->stack->pop();

$args = \array_slice($args, 0, $word->getOperandsCount());

$result = \call_user_func_array($word->getCallback(), $args);

if ( !\is_null($result) ) {
	foreach ( $result as $res ) {
		$this->stack->push($res);
	}
}


?

PHP — -. ( , ), , , .

- , , - — .
- « , » — .

- , — , , , , , .

-))


, , Google Code, : code.google.com/p/php-forth/source/browse/trunk

GPL v.3


  1. ru.wikipedia.org/wiki/%D0%A4%D0%BE%D1%80%D1%82_%28%D1%8F%D0%B7%D1%8B%D0%BA_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F%29
  2. ru.wikipedia.org/wiki/%D0%A1%D1%82%D0%B5%D0%BA
  3. ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%80%D0%B0%D1%82%D0%BD%D0%B0%D1%8F_%D0%BF%D0%BE%D0%BB%D1%8C%D1%81%D0%BA%D0%B0%D1%8F_%D0%BD%D0%BE%D1%82%D0%B0%D1%86%D0%B8%D1%8F
  4. , , , , ...

Source: https://habr.com/ru/post/114666/


All Articles