Skip to content

Instantly share code, notes, and snippets.

@necromant2005
Forked from denji/Phalcon-Zephir.md
Created March 17, 2016 04:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save necromant2005/92a26fd33604d5c2d825 to your computer and use it in GitHub Desktop.
Save necromant2005/92a26fd33604d5c2d825 to your computer and use it in GitHub Desktop.
Zephir write your PHP Extension

About this article will do the following things:

  • Install & Setup
  • Write a simple Router
  • Zephir rewritten version
  • Extension installation and testing

Installation

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!

Write a simple Router

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>

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; // 所有 Assign 的動作都要用 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)

Installation and Testing

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

http://localhost/app/home

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!)

Link's

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment