- Install & Setup
- Write a simple Router
- Zephir rewritten version
- Extension installation and testing
First, we need to install dependencies.
brew install re2c
brew install json-c
But it seems when you install XCode re2c already have, but the version I have in the system is also more than Homebrew also new (basically have installed the messages out of the class would not have again installed ⋯ ⋯)
Because Zephir does not seem to feature a single executable file, so I personally used to put ~/.tools
folder inside, and general tools separate.
cd ~/.tools
git clone https://github.com/phalcon/zephir
cd zephir
Because there is no Mac /opt/local/lib directory, we want to edit install this file.
The -L/opt/local/lib
this deletion (let the compiler do not find in this directory when the relevant Library)
The modified install gcc command inside the president about this
gcc -Wl,-rpath /usr/local/lib -I/usr/local/lib -L/usr/local/lib -g3 parser.c scanner.c -ljson -ljson-c -o ../bin/zephir-parser
After the install you can
./install
Then you can modify ~/.bashrc
or related files, add the following line
export PATH=$PATH:~/.tools/zephir/bin
Re-opened Terminal or enter source ~/.bashrc
after, you can directly use zephir command it!
To change can be observed, let's use PHP to do a simple test Router.
Basically will http://localhost/myApp/index
turn into $controller = new MyApp(); $controller->index()
syntax.
Basically here is not to describe implementations, the following is an example of using the Router source:
<?php
namespace MyRouter;
class Router
{
protected $basePath = '';
protected $currentPath = '';
protected $defaultMethod = '';
public $notFound = null;
public function __construct($basePath = '') {
$this->basePath = $basePath;
$this->defaultMethod = 'index';
}
/**
* Dispatch
*
* Create class instance and call method
*/
public function dispatch()
{
$parseURI = $this->parseURI();
if (!empty($this->basePath) && $this->basePath == $parseURI[0]) {
$parseURI = array_slice($parseURI, 1);
}
$class = null;
$method = null;
if (isset($parseURI[0])) {
$class = $parseURI[0];
$class = ucwords($class);
}
if (isset($parseURI[1])) {
$method = $parseURI[1];
}
if (is_null($class) || !class_exists($class)) {
$this->error(404);
return;
}
$classInstance = new $class;
if (is_null($method)) {
$this->callMethod($classInstance, $this->defaultMethod);
return;
}
$this->callMethod($classInstance, $method);
}
/**
* Call Method
*
* @param object $class
* @param string $method
*/
private function callMethod($class, $method)
{
if (is_callable(array($class, $method))) {
call_user_func(array($class, $method));
} else {
$this->error(404);
}
}
/**
* Error
*
* @param int $code
*/
public function error($code = 500)
{
if ($code == 404) {
if (is_callable($this->notFound)) {
call_user_func($this->notFound);
} else {
echo '404 Not Found';
}
} else {
echo "Error {$code}";
}
}
/**
* Parse URI
*
* Analytic URL and turn into class and method
*
* return array [$class, $method]
*/
protected function parseURI()
{
$currentURI = $_SERVER['REQUEST_URI'];
$pattern = '#/([a-z][a-z0-9-]*)#i';
$matches = array();
preg_match_all($pattern, $currentURI, $matches);
return array_slice($matches, 1)[0];
}
}
Use (index.php for example):
<?php
require 'Router.php';
// require some class for dispath
$router = new MyRouter\Router();
$router->dispatch();
You also need a Rewrite Rule to convert (here using Laravel's. .htaccess)
<IFModule mod_rewrite.c>
Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
</IfModule>
You also need a Rewrite Rule to convert (here using Laravel's. nginx)
server {
listen 80;
listen [::]:80 ipv6only=on; # disallow ipv6-over-ipv4 encapsulation, clear traffic
server_name localhost;
root /var/www/laravel/public;
location / {
index index.php index.html index.htm;
try_files $uri $uri/ =404;
}
location ~ \.php$ {
try_files $uri /index.php =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php7.0-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
After basically operate on to rewrite Zephir version of it!
Zephir rewritten version
While basically similar and PHP, but there are still many Syntax differences, it is recommended that you first read a little (not hard to learn a new language easier than more!)
To initialize the beginning of the project, I first create a myExtension placed my PHP Extension project, and then build a MyRouter side project.
mkdir -p ~/myExtension/MyRouter
cd ~/myExtension/MyRouter
zephir init
Upon completion, the directory should be more than a few files.
- config.json - profile, which is what should be written namepsace
- ext/ - will be the last generation of PHP Extension folder found in this data
- myrouter/ - placed zep file directory (similar to the Class directory rules PSR-0, but all lowercase).
Then go to just the Router.php copy, rename, and then proceed to router.zep rewritten.
Here are a lot of mine (I find Syntax, Compile Error super long, are illustrated by the comments)
myrouter/router.zep
namespace MyRouter;
class Router {
// You can simply remove $ (although there does not seem to be as $ error)
protected basePath = "";
protected currentPath = "";
protected defaultMethod = "";
public notFound = null;
public function __construct(string basePath = null) {
let this->basePath = basePath; // All Assign the action to use let
let this->defaultMethod = "index";
}
/**
* Dispatch
*
* Create class instance and call method
*/
public function dispatch()
{
var parseURI; // Array of such class are classified in Dynamic Variable inside, with var assignment (could not tell by var safer)
let parseURI = []; // Let him do this action judged Array (Official Blog has another approach, not tested)
let parseURI = this->parseURI(); // Get good Array analysis methods from parseURI
if !empty(this->basePath) && this->basePath == parseURI[0] {
let parseURI = array_slice(parseURI, 1); // All the PHP Function / Class basically can directly access
}
var className;
var method;
var value; // The following will use fetch instead of isset (official blog, said to be so used) so he must first define a variable to
let className = null; // Given an initial value, if not to do this action behind is_null () checks will allow direct die becomes PHP Process
// --- The following is speculation, because the problems encountered in this, but the relationship needs to be clarified in detail ---
// On this part of the explanation is also given Tuu greatly, because the underlying or C so leave Scope memory purge, it will segfault
// About Segmentation fault (segfault) because there is not touched, so being the first to collect information on behalf of understanding after sharing details
let method = null;
if fetch value, parseURI[0] { // Isset same effect with this wording, not the same side comparison
let className = value;
let className = ucwords(className);
}
if fetch value, parseURI[1] {
let method = parseURI[1];
}
if is_null(className) || !class_exists(className) {
this->error(404);
return;
}
/**
* This is because PHP can use new $ someClass; way to generate new object (object name instead of using a variable)
* But Zephir put your variables as Class Name so I can not produce normal, then the method of treatment by class_alias
* Class_alias to pass two parameters (string) The first one is the original category, and the second is his name anonymous class
* So through this method, all incoming Class Name Router are diverted into a unified ProxyClass to produce examples of the use
*/
// class_alias(className, "ProxyClass"); // Note that the string always use double quotes, single quotes are treated as char
var classInstance;
//let classInstance = new ProxyClass;
var classInstance = create_instance(className); // Tuu greatly provides the correct usage, the compiler will not be warned!
// create_instance_params(className, params) There is a parameter usage
if method == null {
this->callMethod(classInstance, this->defaultMethod);
return;
}
this->callMethod(classInstance, method);
}
/**
* Call Method
*
* @param object $class
* @param string $method
*/
private function callMethod(var instance, string method) {
if is_callable([instance, method]) { // With [] Array is directly attributable to the accepted (perhaps a follow-up of the new features PHP 5.4)
call_user_func([instance, method]);
} else {
this->error(404);
}
}
/**
* Error
*
* @param int $code
*/
public function error(int code = 500) {
if(code == 404) {
if(is_callable(this->notFound)) {
call_user_func(this->notFound);
} else {
echo "404 Not Found";
}
} else {
echo "Error {code}";
}
}
/**
* Parse URI
*
* Analytic URL and turn into class and method
*
* return array [$class, $method]
*/
protected function parseURI()
{
var currentURI;
let currentURI = _SERVER["REQUEST_URI"];
var pattern = "@/([a-z][a-z0-9-]*)@i"; // Here with \/ go jump off do not know why to be wrong, but to use other delimiters
var matches;
let matches = [];
preg_match_all(pattern, currentURI, matches);
var schema;
let schema = array_slice(matches, 1);
return schema[0];
}
}
Once complete, execute the command in the directory
zephir [compile]
compile can be omitted, but I seem to find any help for command run support, now known init and compile two (afar)
Because I usually use PHPBrew to construct PHP test environment, the following example is copied to PHPBrew the Extension directory.
sudo cp ext/modules/myrouter.so ~/path/to/your/php/extensions/
phpbrew ext enable myrouter
sudo apachectl graceful
PHPBrew provides a convenient command to enable the extension is basically to add php.ini extension=myrouter.so
ready to use!
Finally, we re-edit index.php
to use Extension
<?php
require("Router.php");
// require some class for dispath
$router = new MyRouter\Router();
$router->dispatch();
After reopening, if normal operation is a success!
Note: The above did not produce any Router can be read into the Class everyone can try to join, the following sample code
index.php:
<?php
class App {
public function index() {
echo "Hello, this index";
}
public function home() {
echo "Hello, you should see this when open /app/home";
}
}
$router = new MyRouter\Router();
$router->dispatch();
So, what can be done with Zephir?
- Improve program performance bottlenecks original (probably not change the status of the language in the next)
- Commercial use (encrypted code)
- Use in extreme environments (like the case of insufficient memory)
- Pure fun
- Development of a large-scale PHP framework, something to try to change (Phalcon)
- Perhaps you can think of other ⋯ ⋯
At least I think that PHP has opened up a new path to take, but I think Zephir Phaclon team will be able to change a lot of things.
Currently I recommend others to learn PHP reason, I will use these two:
- Easy access to the operating environment, demand fewer permissions problem
- Getting started is easy to learn, to construct a sense of accomplishment
Zephir I want more of it XDD can also add a "super-fast write simple PHP Website" and the like (Written promise to write PHP Rebot very easy ah, efficient robots, used to analyze the data is very handy!)
厉害 赞