当有__construct()元素时,将类转换为函数

时间:2012-11-04 19:09:30

标签: php oop class function

我正在学习PHP(不断),我前段时间创建了一个处理翻译的课程。我想emulate gettext但是从数据库中获取翻译的字符串。但是,现在我再次看到它,我不喜欢它,作为一个类,称之为我需要使用$Translate->text('String_keyword');。我不想要使用$T->a('String_keyword');,因为这完全不直观。

我一直在考虑如何使用简单的_('String_keyword') gettext样式调用它,但是从我从SO中学到的东西,我还没有找到'实现这一目标的绝佳方式。我需要以某种方式将默认语言传递给函数,我不想在每次调用它时传递它,因为它将是_('String_keyword', $User->get('Language')))。我也不想在_()函数中包含用户检测脚本,因为它只需要运行一次而不是每次都运行。

最简单的方法是使用GLOBALS,但我在这里已经知道它们完全被禁止了(这可能是can use them?}的唯一情况,然后我想DEFINE一个使用用户语言的变量,如define ( USER_LANGUAGE , $User->get('Language') ),但它似乎与全局相同。这些是我可以看到的两个主要选项,我知道还有其他一些方法,比如依赖注入,但它们似乎为一个如此简单的请求添加了太多的复杂性,我还没有时间深入研究它们。

我正在考虑首先创建一个包装器来测试它。像这样:

function _($Id, $Arg = null)
  {
  $Translate = new Translate (USER_LANGUAGE);
  return $Translate -> text($Id, $Arg)
  }

这是翻译代码。在创建之前检测语言并将其传递给对象。

// Translate text strings
// TO DO: SHOULD, SHOULD change it to PDO! Also, merge the 2 tables into 1
class Translate
  {
  private $Lang;

  function __construct ($Lang)
    {
    $this->Lang = $Lang;
    }

  // Clever. Adds the translation so when codding I don't get annoyed.
  private function add ($Id, $Text)
    {
    $sql="INSERT INTO htranslations (keyword, en, page, last) VALUES ('$Id', '$Text', '".$_SERVER['PHP_SELF']."', now())";

    mysql_query($sql);
    }

  private function retrieve ( $Id )
    {
    $table = is_int ($Id) ? "translations" : "htranslations";      // A small tweak to support the two tables, but they should be merged.
    $results = mysql_query ("SELECT ".mysql_real_escape_string($this->Lang)." FROM ".$table." WHERE keyword='".mysql_real_escape_string($Id)."'");
    $row = mysql_fetch_assoc ($results);
    return mysql_num_rows ($results) ? stripslashes ($row[$this->Lang]) : null;
    }

  // If needed to insert a name, for example, pass it in the $Arg
  public function text($Id, $Arg = null)
    {
    $Text = $this->retrieve($Id);
    if (empty($Text))
      {
      $Text = str_replace("_", " ", $Id);  // If not found, replace all "_" with " " from the input string.
      $this->add($Id, $Text);
      }
    return str_replace("%s", $Arg, $Text);    // Not likely to have more than 2 variables into a single string.
    }
  }

您如何以正确而简单(编码)的方式实现这一目标?任何提议的方法是否有效,或者您能找到更好的方法吗?

2 个答案:

答案 0 :(得分:6)

如果问题只是那个

$Translate->text('String_keyword');

感觉很长,然后考虑通过实施__invoke将Translate对象变为Functor:

class Translate
{
    // all your PHP code you already have

    public function __invoke($keyword, $Arg = null)
    {
        return $this->text($keyword, $Arg)
    }
}

然后,您可以定期使用所有必需的依赖项和设置实例化对象并调用它:

$_ = new Translate(/* whatever it needs */);
echo $_('Hallo Welt');

这不会引入相同数量的耦合和摆弄全局范围,正如您目前考虑通过包装函数或其他地方建议的Registry / Singleton解决方案引入的那样。唯一的缺点是对象变量的非语句命名为$_()

答案 1 :(得分:1)

我会使用注册表或使Translate成为单身人士。当我第一次初始化它时,我将传递在请求的引导阶段不会的语言。然后我会在必要时添加更改语言的方法。

完成后,您的功能变得非常简单:

// singleton version
function _($id, $arg = null) {
   return Translate::getInstance()->text($id, $arg);
}


// registry version
function _($id, $arg = null) {
  return Registry::get('Translate')->text($id, $arg);
}

然后在你的bootstap阶段你会做类似的事情:

$lang = get_user_lang(); // replace with however you do this

//registry version
Registry::set('Tranlaste', new Translate($lang));

// or the singleton version
// youd use create instance instead of getInstance 
// so you can manage the case where you try to call 
// getInstance before a language is set
Translate::createInstance($lang);