基于对象类型的PHP最佳操作实践

时间:2015-07-05 19:09:57

标签: php laravel

我有一个PHP / Laravel最佳实践问题。

以下是该方案: 我有一个带有“type”属性的对象。 type属性将设置为某种整数。

根据对象中的“type”整数,必须执行不同的操作。

处理此对象的最佳方法是什么?我正在拼命想到一种避免使用一大堆if / else语句的方法,因为这种方法感觉非常错误和丑陋。

即。我不想要这个:

if($obj->type == 1) {
    //process actions for type 1
}
else if($obj->type == 2){
    //process actions for type 2
}

非常感谢任何建议。

谢谢!

2 个答案:

答案 0 :(得分:2)

感谢@Ryan Vincent,我找到了这个资源(https://sourcemaking.com/design_patterns/strategy/php),并稍微改变了策略设计模式。为避免硬编码类型值,请检查在StrategyContext::__construct方法中如何完成动态类加载。新类实例由$type变量名称启动。 PHP中的类名应为strings,因此这种方式强制类型strings不仅仅是数字。

与文章中的原始示例不同,我将StrategyContext附加到book对象并使用策略包装get方法以更好地使用book对象。 不幸的是,如果业务逻辑将以某种方式存在于您的代码中,则需要对其进行硬编码。使用此方法,您不需要对每种类型进行硬编码,但您需要为每种类型创建一个策略类。在示例中,我们提供了StrategyCapsStrategyStarsStrategyExclaim策略。因此,我们的类型仅限于CapsStarsExclaim

我没有在生产环境中尝试这段代码,但您可以通过示例获得一个起点。

同样对于动态加载,您也可以从这个问题中受益。instantiate a class from a variable in PHP?

希望它有所帮助,

<?php
interface StrategyInterface {
    public function showTitle($title);
    public function showAuthor($author);
}

class StrategyContext  implements StrategyInterface {
    private $strategy = NULL; 

    public function __construct($type) {

        //Dynamic class loading per type
        $classname="Strategy{$type}";
        if(class_exists($classname)) {
          $this->strategy = new $classname();
        } else {
          throw new Exception("Strategy not found", 1);
        }

    }
    public function showTitle($title) {
      return $this->strategy->showTitle($title);
    }

    public function showAuthor($author) {
      return $this->strategy->showAuthor($author);
    }
}


class StrategyCaps implements StrategyInterface {
    public function showTitle($title) {
        return strtoupper ($title);
    }

    public function showAuthor($author) {
        return strtoupper ($author);
    }
}

class StrategyExclaim implements StrategyInterface {
    public function showTitle($title) {
        return Str_replace(' ','!',$title);
    }
    public function showAuthor($author) {
        return Str_replace(' ','!',$author);
    }
}

class StrategyStars implements StrategyInterface {
    public function showTitle($title) {
        return Str_replace(' ','*',$title);
    }    

    public function showAuthor($author) {
        return Str_replace(' ','*',$author);
    }

}

class Book {
    private $author;
    private $title;
    private $strategy;

    function __construct($strategy, $title_in, $author_in) {
        $this->strategy = new StrategyContext($strategy);
        $this->author = $author_in;
        $this->title  = $title_in;
    }
    function getAuthor() {
        return $this->strategy->showAuthor($this->author);
    }
    function getTitle() {
        return $this->strategy->showTitle($this->title);
    }
    function getAuthorAndTitle() {
        return $this->getTitle() . ' by ' . $this->getAuthor();
    }
}

writeln('BEGIN TESTING STRATEGY PATTERN');
writeln('');

$type = 'Caps';
$book = new Book($type, 'PHP for Cats','Zeev Suraski');
writeln($book->getAuthorAndTitle());


$type = 'Exclaim';
$book = new Book($type, 'PHP for Unicorns','Rasmus Lerdorf');
writeln($book->getAuthorAndTitle());


$type = 'Stars';
$book = new Book($type, 'PHP for Ponys','Andi Gutmans');
writeln($book->getAuthorAndTitle());


function writeln($line_in) {
  echo $line_in.PHP_EOL;
}

更新

因此,如果您使用的是ORM,我们可以假设Book是您的模型类。我对Eloquent以及它如何处理数据绑定等方面没有任何了解,所以我会尽可能简单。所以我假设您可以使用带有数据库绑定数据的构造函数。

将您的StrategyContext和实际策略类 - 您的业务逻辑编码 - 作为服务进行编码并使用依赖注入,同时找出您将使用的策略。这样,您可以根据type变量将所有策略绑定到模型对象中。

Book类的更新版本,

class Book {
    private $author = "Zeev Suraski";
    private $title = "PHP for Cats";
    private $strategy;
    private $type = 'Caps';

    function __construct() {
        $this->strategy = new StrategyContext($this->type); //Dependency injection here
    }

    function getAuthor() {
        return $this->strategy->showAuthor($this->author);
    }

    function getTitle() {
        return $this->strategy->showTitle($this->title);
    }

    function getAuthorAndTitle() {
        return $this->getTitle() . ' by ' . $this->getAuthor();
    }

    function setType($type) {
      $this->type = $type;
    }

    function setStrategy($type=null) {
      if($type==null) {
        $this->strategy = new StrategyContext($this->type); //Dependency injection here
      } else {
        $this->strategy = new StrategyContext($type); //Dependency injection here
        $this->setType($type);
      }
    }

}


writeln('BEGIN TESTING STRATEGY PATTERN');
writeln('');

$book = new Book();
writeln($book->getAuthorAndTitle());


$type = 'Exclaim';
$book->setType($type);
$book->setStrategy();
writeln($book->getAuthorAndTitle());


$type = 'Stars';
$book->setStrategy($type);
writeln($book->getAuthorAndTitle());

function writeln($line_in) {
  echo $line_in.PHP_EOL;
}

答案 1 :(得分:0)

我会使用PHP的switch语句。例如,

switch($obj->type) {
    case 1:
        // do something
        break;
    case 2:
        // do something else
        break;
    default:
        // default actions
        break;
}

这里break用于停止整个switch语句的执行。如果没有中断,代码执行可能会落到下一个案例中。这有时是令人满意的行为。如果你想要案例1和2运行相同的代码,你可以将案例1留空并在案例2中写下你的所有代码。这样当满足案例1条件时,不会运行与案例1相关的代码,但是如果没有break语句,代码执行将在到达案例2中的break语句之前继续进入案例2。