J'utilise PHP 5 et j'ai entendu parler d'une nouvelle fonctionnalité de l'approche orientée objet, appelée «chaînage de méthodes». C'est quoi exactement? Comment le mettre en œuvre?
J'utilise PHP 5 et j'ai entendu parler d'une nouvelle fonctionnalité de l'approche orientée objet, appelée «chaînage de méthodes». C'est quoi exactement? Comment le mettre en œuvre?
Réponses:
C'est plutôt simple en fait, vous avez une série de méthodes de mutation qui retournent toutes les objets originaux (ou autres), de cette façon vous pouvez continuer à appeler des méthodes sur l'objet retourné.
<?php
class fakeString
{
private $str;
function __construct()
{
$this->str = "";
}
function addA()
{
$this->str .= "a";
return $this;
}
function addB()
{
$this->str .= "b";
return $this;
}
function getStr()
{
return $this->str;
}
}
$a = new fakeString();
echo $a->addA()->addB()->getStr();
Cela génère "ab"
$foo->setBar(1)->setBaz(2)
vs $table->select()->from('foo')->where('bar = 1')->order('ASC)
. Ce dernier couvre plusieurs objets.
$a = (new fakeString())->addA()->addB()->getStr();
En gros, vous prenez un objet:
$obj = new ObjectWithChainableMethods();
Appelez une méthode qui fait effectivement un return $this;
à la fin:
$obj->doSomething();
Comme il renvoie le même objet, ou plutôt une référence au même objet, vous pouvez continuer à appeler des méthodes de la même classe à partir de la valeur de retour, comme ceci:
$obj->doSomething()->doSomethingElse();
C'est ça, vraiment. Deux choses importantes:
Comme vous le notez, il s'agit uniquement de PHP 5. Cela ne fonctionnera pas correctement en PHP 4 car il renvoie les objets par valeur et cela signifie que vous appelez des méthodes sur différentes copies d'un objet, ce qui briserait votre code.
Encore une fois, vous devez renvoyer l'objet dans vos méthodes chaînables:
public function doSomething() {
// Do stuff
return $this;
}
public function doSomethingElse() {
// Do more stuff
return $this;
}
return &$this
en PHP4?
Essayez ce code:
<?php
class DBManager
{
private $selectables = array();
private $table;
private $whereClause;
private $limit;
public function select() {
$this->selectables = func_get_args();
return $this;
}
public function from($table) {
$this->table = $table;
return $this;
}
public function where($where) {
$this->whereClause = $where;
return $this;
}
public function limit($limit) {
$this->limit = $limit;
return $this;
}
public function result() {
$query[] = "SELECT";
// if the selectables array is empty, select all
if (empty($this->selectables)) {
$query[] = "*";
}
// else select according to selectables
else {
$query[] = join(', ', $this->selectables);
}
$query[] = "FROM";
$query[] = $this->table;
if (!empty($this->whereClause)) {
$query[] = "WHERE";
$query[] = $this->whereClause;
}
if (!empty($this->limit)) {
$query[] = "LIMIT";
$query[] = $this->limit;
}
return join(' ', $query);
}
}
// Now to use the class and see how METHOD CHAINING works
// let us instantiate the class DBManager
$testOne = new DBManager();
$testOne->select()->from('users');
echo $testOne->result();
// OR
echo $testOne->select()->from('users')->result();
// both displays: 'SELECT * FROM users'
$testTwo = new DBManager();
$testTwo->select()->from('posts')->where('id > 200')->limit(10);
echo $testTwo->result();
// this displays: 'SELECT * FROM posts WHERE id > 200 LIMIT 10'
$testThree = new DBManager();
$testThree->select(
'firstname',
'email',
'country',
'city'
)->from('users')->where('id = 2399');
echo $testThree->result();
// this will display:
// 'SELECT firstname, email, country, city FROM users WHERE id = 2399'
?>
Le chaînage de méthodes signifie que vous pouvez enchaîner les appels de méthode:
$object->method1()->method2()->method3()
Cela signifie que method1 () doit renvoyer un objet et method2 () reçoit le résultat de method1 (). Method2 () passe ensuite la valeur de retour à method3 ().
Bon article: http://www.talkphp.com/advanced-php-programming/1163-php5-method-chaining.html
class Maker
{
private static $result = null;
private static $delimiter = '.';
private static $data = [];
public static function words($words)
{
if( !empty($words) && count($words) )
{
foreach ($words as $w)
{
self::$data[] = $w;
}
}
return new static;
}
public static function concate($delimiter)
{
self::$delimiter = $delimiter;
foreach (self::$data as $d)
{
self::$result .= $d.$delimiter;
}
return new static;
}
public static function get()
{
return rtrim(self::$result, self::$delimiter);
}
}
echo Maker::words(['foo', 'bob', 'bar'])->concate('-')->get();
echo "<br />";
echo Maker::words(['foo', 'bob', 'bar'])->concate('>')->get();
Il y a 49 lignes de code qui vous permettent d'enchaîner des méthodes sur des tableaux comme celui-ci:
$fruits = new Arr(array("lemon", "orange", "banana", "apple"));
$fruits->change_key_case(CASE_UPPER)->filter()->walk(function($value,$key) {
echo $key.': '.$value."\r\n";
});
Voir cet article qui vous montre comment enchaîner les soixante-dix fonctions array_ de PHP.
http://domexception.blogspot.fi/2013/08/php-magic-methods-and-arrayobject.html
Si vous voulez dire le chaînage de méthodes comme en JavaScript (ou que certaines personnes gardent à l'esprit jQuery), pourquoi ne pas simplement prendre une bibliothèque qui apporte ce développement. expérience en PHP? Par exemple Extras - https://dsheiko.github.io/extras/ Celui-ci étend les types PHP avec les méthodes JavaScript et Underscore et fournit le chaînage:
Vous pouvez chaîner un type particulier:
<?php
use \Dsheiko\Extras\Arrays;
// Chain of calls
$res = Arrays::chain([1, 2, 3])
->map(function($num){ return $num + 1; })
->filter(function($num){ return $num > 1; })
->reduce(function($carry, $num){ return $carry + $num; }, 0)
->value();
ou
<?php
use \Dsheiko\Extras\Strings;
$res = Strings::from( " 12345 " )
->replace("/1/", "5")
->replace("/2/", "5")
->trim()
->substr(1, 3)
->get();
echo $res; // "534"
Vous pouvez également devenir polymorphe:
<?php
use \Dsheiko\Extras\Any;
$res = Any::chain(new \ArrayObject([1,2,3]))
->toArray() // value is [1,2,3]
->map(function($num){ return [ "num" => $num ]; })
// value is [[ "num" => 1, ..]]
->reduce(function($carry, $arr){
$carry .= $arr["num"];
return $carry;
}, "") // value is "123"
->replace("/2/", "") // value is "13"
->then(function($value){
if (empty($value)) {
throw new \Exception("Empty value");
}
return $value;
})
->value();
echo $res; // "13"
Voici mon modèle qui est capable de trouver par ID dans la base de données. La méthode with ($ data) est mes paramètres supplémentaires pour la relation, donc je retourne le $ this qui est l'objet lui-même. Sur mon contrôleur, je peux l'enchaîner.
class JobModel implements JobInterface{
protected $job;
public function __construct(Model $job){
$this->job = $job;
}
public function find($id){
return $this->job->find($id);
}
public function with($data=[]){
$this->job = $this->job->with($params);
return $this;
}
}
class JobController{
protected $job;
public function __construct(JobModel $job){
$this->job = $job;
}
public function index(){
// chaining must be in order
$this->job->with(['data'])->find(1);
}
}