Dynamic proxy with python, ruby, PHP

Introduction

This article is the 20th day of "WACUL Advent Calendar 2016". Recently, I personally read back metaprogramming ruby and used it partly at work ~ ~ There is no fresh material to talk about ~ ~, so this time I will write about dynamic proxy.

What is a dynamic proxy?

Actually, I'm not sure how common this word is ... Personally, "a programming pattern that receives the name and parameters of an undefined method and delegates the desired processing to another object" I recognize that.

When to use

This is useful when you want to write a wrapper for an external system.

For example, suppose you want to write a client library that uses an external REST api. For the sake of simplicity, let's limit ourselves to GET.

GET /api/hoge

To execute, for example, using requests in python

import requests

class Client:
    def hoge(self):
        return requests.get('/api/hoge')

client = Client()
client.hoge()

And so on. Nothing is difficult. However, in this case, if fuga, piyo, etc. increase

class Client:
    def hoge(self):
        return requests.get('/api/hoge')
    def fuga(self):
        return requests.get('/api/fuga')
    def piyo(self):
        return requests.get('/api/piyo')

It is difficult because the number of copies is increasing.

Therefore, we use "a special method that is called when a method or property cannot be found". In python, methods and properties are equal and object attributes, so you can use ``` getattr` ``.

class Client:
    def __getattr__(self, name):
        def _func(*args, **kwargs):
            return requests.get('/api/' + name)
        return _func

Now you can support client.hoge (), client.fuga () and client.piyo (), and best of all, you don't have to maintain the Client class as more apis are added in the future. Also, depending on the implementation of `` `_func```, you are free to handle the parameters you pass to client.method.

Dynamic proxy in Ruby and PHP

First, let's do it in Ruby. This time, I will use method_missing because I want to not only reduce the amount of code but also dynamically correspond to unknown specifications.

a.rb


class A
  def method_missing(name, *args, &blk)
    p name.to_s
    p args
    return if not block_given?
    blk.call
  end
end

a = A.new
a.hoge
a.fuga(1, 2, 3)
a.piyo do |i, j|
  p "piyopiyo"
end

When you run it, it looks like this

"hoge"
[]
"fuga"
[1, 2, 3]
"piyo"
[]
"piyopiyo"

Next is PHP. Use `__ call`. I remembered it when I was writing at work ~~ when it was written ~~. It feels good when combined with Reflection. For static methods, there is another method called __callStatic.

a.php


<?php

class A
{
    public function __call($name, $args)
    {
        var_dump($name);
        var_dump($args);
    }
}

$a = new A();
$a->hoge();
$a->fuga("fugaarg");

When I run it with cli, it looks like this

string(4) "hoge"
array(0) {
}
string(4) "fuga"
array(1) {
  [0]=>
  string(7) "fugaarg"
}

Be careful

If you use it too much, the code tends to be difficult to read. Use it systematically.

Recommended Posts

Dynamic proxy with python, ruby, PHP
Realize PHP / Python generator with Golang / Ruby
I tried using mecab with python2.7, ruby2.3, php7
Java VS PHP VS Python VS Ruby
Zundokokiyoshi with python / ruby / Lua
About Perl, Python, PHP, Ruby
Solving with Ruby and Python AtCoder ABC178 D Dynamic programming
Scraping with Node, Ruby and Python
Overlapping combinations with limits in Python / Ruby / PHP / Golang (Go)
Solving with Ruby and Python AtCoder ABC011 C Dynamic programming
Solving with Ruby and Python AtCoder ABC153 E Dynamic programming
Handling regular expressions with PHP / Python
Send image with python, save with php
PHP / Python / Ruby sample hitting Path API
[Basic grammar] Differences between Ruby / Python / PHP
Try calling Python from Ruby with thrift
Encrypt with Ruby (Rails) and decrypt with Python
Easy web scraping with Python and Ruby
FizzBuzz with Python3
Scraping with Python
Statistics with python
Scraping with Python
Python with Go
Twilio with Python
Python dynamic typing
Integrate with Python
Play with 2016-Python
AES256 with python
Tested with Python
python starts with ()
with syntax (Python)
Bingo with python
Zundokokiyoshi with python
I tried hitting Mastodon API with Ruby (Faraday) / Python (Pycurl) / PHP (Curl)
Excel with Python
Microcomputer with Python
Cast with python
[Various image analysis with plotly] Dynamic visualization with plotly [python, image]
[Write to map with plotly] Dynamic visualization with plotly [python]
Grouping combination in Python / Ruby / PHP / Golang (Go)
Serial communication with Python
Zip, unzip with python
Django 1.11 started with Python3.6
Primality test with Python
Python with eclipse + PyDev.
2014 Web Application Framework Trends (PHP / Java / Ruby / Python / Perl)
Socket communication with Python
Data analysis with python 2
Scraping with Python (preparation)
Try scraping with Python.
[Docker] Tutorial (Python + php)
Dynamic HTML pages made with AWS Lambda and Python
Learning Python with ChemTHEATER 03
Sequential search with Python
"Object-oriented" learning with python
Run Python with VBA
Handling yaml with python
Solve AtCoder 167 with python
[Python] Use JSON with Python
Learning Python with ChemTHEATER 05-1
Learn Python with ChemTHEATER