Insert a green onion into the pig's nose

Source: Internet
Author: User
PHP has some dynamic language features, but it is not thorough. although the mark of PHP is an elephant, its nose is too short to reach things, but it is like a pig. this article aims to explore a method to make PHP more dynamic, mainly to simulate prototype inheritance of Javascript. since it is a simulation, it does not really make PHP dynamic, just plug in PHP with some dynamic language features, but not completely. although the mark of PHP is an elephant, its nose is too short to reach things, but it is like a pig. this article aims to explore a method to make PHP more dynamic, mainly to simulate prototype inheritance of Javascript. since it is a simulation, it does not really make PHP dynamic, just insert a Onion to make it more "like" a little.

I. Basic operations
You can use the prototype of Javascript to dynamically add attributes to an object, as shown in the following code:
Object.prototype.greeting = 'Hello'var o = new Objectalert(o.greeting)

The built-in Object of Js can be viewed as a "class". any Js "class" has a prototype built-in Object. PHP can simulate it as follows:
error_reporting(E_ALL);class Object{     public static $prototype;     protected function __get($var) {         if ( isset(self::$prototype->$var) ) {             return self::$prototype->$var; }}}

Then we can:
Object: $ prototype-> greeting = 'hello'; $ o = new Object; echo $ o-> greeting; // output Hello

The automatic transformation feature of PHP is used here. in PHP, we need to declare an array without $ var = array () and then $ var [] = some_value. directly use the latter to get an array; when $ object-> var is directly used, $ object is automatically defined as a stdClass object. this solves the problem that public static $ prototype = new stdClass cannot be declared when defining static attributes in the class.

Dynamically add methods to "class" in Js:
Object.prototype.say = function(word) { alert(word) }o.say('Hi')

Simulate in PHP:
error_reporting(E_ALL);class Object{     public static $prototype;     protected function __get($var) {         if ( isset(self::$prototype->$var) ) {             return self::$prototype->$var; }}     protected function __call($call, $params) {         if ( isset(self::$prototype->$call) && is_callable(self::$prototype->$call) ) {             return call_user_func_array(self::$prototype->$call, $params); }         else {             throw new Exception('Call to undefined method: ' . __CLASS__ . "::$call()"); }}}

In this way, you can
Object::$prototype->say = create_function('$word', 'echo $word;');$o->say('Hi');

However, the result returned by create_function in PHP is not equivalent to the Function object in Js. the Function object in Js is a closure, which can directly call the host attributes, such
Object.prototype.rock = function() { alert(this.oops) }o.oops = 'Oops'o.rock()

But in PHP, we cannot write
Object::$prototype->rock = create_function('', 'echo $this->oops;');$o->oops = 'Oops';$o->rock();

Fatal error: Using $ this when not in object context will be reported, because create_function returns an anonymous normal function, which has no host. to solve this problem, we need to input the object itself in the parameter, and the $ this variable name cannot be used as the parameter. for now, we use a $ caller variable name:
Object::$prototype->rock = create_function('$caller', 'echo $caller->oops;');$o->oops = 'Oops';$o->rock($o);

It's okay now, but it looks strange. it's not like a dynamic language at all. well ~, The Onion is still a little short, or not "elephant ".

Question:
1. when calling a dynamic method, the object itself needs to be passed. which object is object-oriented?
2. we need to use $ this in the code, which is like object-oriented.

Solution:
1. rewrite a function to replace create_function, and squeeze a parameter $ that in the parameter section as the first parameter, when passing parameters to an anonymous function in _ call, add the object $ this as the first parameter.
2. $ this can be used in the code. in the replacement function, replace $ this with $ that.

We will add a create_method function to it to replace create_function.
function create_method($args, $code) {     if ( preg_match('/\$that\b/', $args) ) {         throw new Exception('Using reserved word \'$that\' as argument'); }     $args = preg_match('/^\s*$/s', $args) ? '$that' : '$that, '. $args;     $code = preg_replace('/\$this\b/', '$that', $code);     return create_function($args, $code); }

$ That, as the "reserved word" in the parameter, will throw an exception when it appears in the parameter section. (in early versions of PHP5, $ that was also a reserved word)

Correspondingly, the _ call in the Object must also be modified.
Class Object {public static $ prototype; protected function _ get ($ var) {if (isset (self: $ prototype-> $ var) {return self :: $ prototype-> $ var ;}} protected function _ call ($ call, $ params) {if (isset (self ::$ prototype-> $ call) & is_callable (self: $ prototype-> $ call) {array_unshift ($ params, $ this); // here! Return call_user_func_array (self: $ prototype-> $ call, $ params);} else {throw new Exception ('Call to undefined method :'. _ CLASS __. ": $ call ()");}}}

Now we can
Object::$prototype->rock = create_method('', 'echo $this->oops;');$o->oops = 'Oops';$o->rock();





II. Inheritance
One of the main features of object-oriented is inheritance, which maximizes the ability to reuse code. However, if you directly use the Object class in the previous example to create an inheritance class, an error will occur because
1. static attributes inherited by subclass $ prototype always belongs to the parent class (no matter whether the $ prototype is a scalar or a list, let alone an object)
2. if the method inherited by the subclass contains the self keyword, self will point to the parent class rather than the subclass.
class Object{     public static $prototype;     protected function __get($var) {         ... }     protected function __call($call, $params) {         ... }}class Test extends Object{}Test::$prototype->greeting = 'Hello';print_r(Object::$prototype);/* outputsstdClass Object(    [greeting] => Hello)*/Test::$prototype->say = create_method('$word', 'echo $word;');$o = new Object;$o->say('Hi');/* outputsHi*/

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.