dongxing2710 2012-08-27 17:31
浏览 31
已采纳

我应该使用静态方法和属性来检测语言并翻译文本吗?

Choices

I am learning OOP PHP, but some things are really confusing. I have a general idea of where to use static methods, but I'm not sure if here it's a good idea.

My questions is about which is actually the best approach for the specific problem I am facing (described below). The general guidelines I've found online didn't help for this specific problem. Here is what I thought (from more likely to be correct to less):

  • Extend the Language class, create a single object (that gets the language in the initialization) and call a method with the $id that would return the translated string.

  • Merge both classes into one. The language would be found when initialized and a method called when needed. But it would behave a little as a God object.

  • Make the Language class static. Therefore I would be able to use it from within the Text. I would create a Text instance and call a method with different $id. Similar to using it with globals. There's almost no other place where I'd need to use the Language class.

  • Extend the Language class with Text, create an object for each translation. This would probably create too much overhead.

  • Not do anything. It's tempting (don't fix it if it's not broken), but I intend to start developing with someone else soon, so clean and clear code is needed.

Code

Now the simple class:

class Language
  {
  public $Lang;
  public function __construct()
    {
    if ( !empty($_POST['lang']) )    // If the user tries to change the language
      {
      $this->Lang = mysql_real_escape_string($_POST['lang']);  // Assign the language to variable.
      $_SESSION['lang'] = $this->Lang;      //Sets the session to have that language.
      if ($_SESSION['logged']==1)          // If user is logged
        {
        $User=$_SESSION['user'];
        mysql_query("UPDATE users SET lang='$this->Lang' WHERE email='$User'") or die(mysql_error());  // Saves the language into user preferences
        }
      }
    else      // If no request is done.
      {
      if ($_SESSION['logged']==1)    // DO. Check for user's language
        {
        $User=mysql_real_escape_string($_SESSION['user']);
        $result=mysql_query("SELECT * FROM users WHERE email='$User'");
        $row=mysql_fetch_array($result);
        $this->Lang=$row['lang'];
        }
      else
        if ( !empty ($_SESSION['lang']))  // If the session exists (not empty)
          $this->Lang = $_SESSION['lang'];  // Assign the session language to variable.
        else          // If it doesn't exist
          $this->Lang = substr ($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);  // Get it from the browser
      }
    //If the language is not supported (or still doesn't exist), then put "en" as default. Supported so far: en, es.
    if ( $this->Lang !== "en" && $this->Lang !== "es") $this->Lang="en";
    }
  }

I have few methods inside this class, but that's the only relevan code here. So I initialize it with $Language=new Language; and then use $Language->Lang; to obtain the user language. So far so good.

This is the function I want to reconvert to a class. It gets an integer or a string, searches it as an id with mysql and returns a translated string in the right language. Now, how do I achieve this? Here it's the text() function. It was used with globals, which is apparently a really bad practice.

function text($Id)
    {
    // Already defined and tested that are valid (sql injection avoided also)
    global $Lang;
    global $Url;
    global $Version;
    global $Banner;
    if (!empty($Url["folder"])) $FullUrl = "/".$Url["folder"]."/";
      else $FullUrl="/";
    if (!is_int($Id)) $Id = mysql_real_escape_string( $Id );

    $numargs = func_num_args();  // Get the number of arguments that are being passed.
    if ($numargs == 2)  // If there are actually two
      $Var=func_get_arg(1);  // Set $Var with the second value (1).

    if (is_int($Id))  // If a number is being passed
      {
        // Add AND page='$FullUrl' to control scope of the strings translated
      $results = mysql_query("SELECT * FROM translations WHERE id='$Id'") or die ('Could not query:' . mysql_error());
      $row = mysql_fetch_assoc($results);
      if (!empty($row[$Lang]) && !isset($Var)) echo stripslashes($row[$Lang]);  // If there is some, echo it
        elseif ($Var==1) return stripslashes($row[$Lang]); // If it is required to be a returned string, send it.
      else error($FullUrl,$Lang);  // If there is nothing there, calls error function.
      }
    else  // If a string is being passed
      {
      $results = mysql_query("SELECT * FROM htranslations WHERE keyword='$Id'") or die ('Could not query:' . mysql_error());
      $row = mysql_fetch_assoc($results);

      if (!empty($row[$Lang]) && !isset($Var)) echo stripslashes($row[$Lang]);  // If it exists in the table, echo it
      elseif (!empty($row[$Lang]) && isset($Var)) return stripslashes($row[$Lang]);
      else  // Else (it doesn't exist)
        {
        $Id = str_replace("_", " ", $Id);  // Replace the "_" with " "
        if (!isset($Var))
          {
          echo $Id;  // Echo the passed string with spaces
          }
        else return $Id;

        $Banner="There might be some misstranslation. Please report if needed.";
        }
      }
    }
  • 写回答

1条回答 默认 最新

  • dongwei3336 2012-09-01 14:42
    关注

    So the text function has lots of side effects; meaning, it's touching a lot of stuff, and sometimes returning and other times printing stuff to standard output. This is usually not good because it is hard to debug, unit-test and refactor

    I would go with option 2: Merge both classes into one. The language would be found when initialized and a method called when needed.

    Below is how I would implement this (I kept as much code intact as possible so you could understand what was changed in regards to OOP. There are many other things I would change; mostly what others have already commented on plus not printing anything from within the method. It's good practice to have methods return something and not modify the application state from within

    Things I changed:

    The text function was actually changing a global variable ($Banner) during certain times, using two global variables ($Url) and ($Lang which is actually from the language object) and then returning an Id from the database or possibly printing to standard output.

    Since moving the text function into the Language class, I converted the global $Lang variable to use the instance variable $Lang of the Language class

    The $Url method is only being used in the text function and thus, can be passed into the text method

    The global variable $Banner is actually being set by the text function which I consider a bad side effect. I decided to replace this code:

    $Banner = "There might be some misstranslation. Please report if needed.";

    with

    return false.

    This way, if the text method returns false, you can set the $Banner variable to "There might be some mistranslation. Please report if needed." which is done from outside of the object.

    Also, I removed the global variable $Version from the text function becaue it was not used within the function

    I would also recommend working on having the text method only return and not print to the standard output. Misstranslation is spelt wrong. It should be mistranslation.

    I hope this helps...

    <?php
    
    class Language {
    
        public $Lang;
    
        public function __construct() {
            if (!empty($_POST['lang'])) {    // If the user tries to change the language
                $this->Lang = mysql_real_escape_string($_POST['lang']);  // Assign the language to variable.
                $_SESSION['lang'] = $this->Lang;      //Sets the session to have that language.
                if ($_SESSION['logged'] == 1) {          // If user is logged
                    $User = $_SESSION['user'];
                    mysql_query("UPDATE users SET lang='$this->Lang' WHERE email='$User'") or die(mysql_error());  // Saves the language into user preferences
                }
            } else {      // If no request is done.
                if ($_SESSION['logged'] == 1) {    // DO. Check for user's language
                    $User = mysql_real_escape_string($_SESSION['user']);
                    $result = mysql_query("SELECT * FROM users WHERE email='$User'");
                    $row = mysql_fetch_array($result);
                    $this->Lang = $row['lang'];
                } else
                if (!empty($_SESSION['lang']))  // If the session exists (not empty)
                    $this->Lang = $_SESSION['lang'];  // Assign the session language to variable.
                else          // If it doesn't exist
                    $this->Lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);  // Get it from the browser
            }
            //If the language is not supported (or still doesn't exist), then put "en" as default. Supported so far: en, es.
            if ($this->Lang !== "en" && $this->Lang !== "es")
                $this->Lang = "en";
        }
    
        public function text($Id, $Url) {
            // Already defined and tested that are valid (sql injection avoided also)
            if (!empty($Url["folder"]))
                $FullUrl = "/" . $Url["folder"] . "/";
            else
                $FullUrl = "/";
            if (!is_int($Id))
                $Id = mysql_real_escape_string($Id);
    
            $numargs = func_num_args();  // Get the number of arguments that are being passed.
            if ($numargs == 2)  // If there are actually two
                $Var = func_get_arg(1);  // Set $Var with the second value (1).
    
            if (is_int($Id)) {  // If a number is being passed
                // Add AND page='$FullUrl' to control scope of the strings translated
                $results = mysql_query("SELECT * FROM translations WHERE id='$Id'") or die('Could not query:' . mysql_error());
                $row = mysql_fetch_assoc($results);
                if (!empty($row[$this->Lang]) && !isset($Var)) {
                    echo stripslashes($row[$this->Lang]);  // If there is some, echo it
                } elseif ($Var == 1) {
                    return stripslashes($row[$this->Lang]); // If it is required to be a returned string, send it.
                } else {
                    error($FullUrl, $this->Lang);  // If there is nothing there, calls error function.
                }
            } else {  // If a string is being passed
                $results = mysql_query("SELECT * FROM htranslations WHERE keyword='$Id'") or die('Could not query:' . mysql_error());
                $row = mysql_fetch_assoc($results);
    
                if (!empty($row[$this->Lang]) && !isset($Var)) {
                    echo stripslashes($row[$this->Lang]);  // If it exists in the table, echo it
                } elseif (!empty($row[$this->Lang]) && isset($Var)) {
                    return stripslashes($row[$this->Lang]);
                } else {  // Else (it doesn't exist)
                    $Id = str_replace("_", " ", $Id);  // Replace the "_" with " "
                    if (!isset($Var)) {
                        echo $Id;  // Echo the passed string with spaces
                    } else {
                        return $Id;
                    }
    
                    return false;
                }
            }
        }
    
    }
    
    ?>
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥100 求数学坐标画圆以及直线的算法
  • ¥100 c语言,请帮蒟蒻写一个题的范例作参考
  • ¥15 名为“Product”的列已属于此 DataTable
  • ¥15 安卓adb backup备份应用数据失败
  • ¥15 eclipse运行项目时遇到的问题
  • ¥15 关于#c##的问题:最近需要用CAT工具Trados进行一些开发
  • ¥15 南大pa1 小游戏没有界面,并且报了如下错误,尝试过换显卡驱动,但是好像不行
  • ¥15 自己瞎改改,结果现在又运行不了了
  • ¥15 链式存储应该如何解决
  • ¥15 没有证书,nginx怎么反向代理到只能接受https的公网网站