4

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.";
        }
      }
    }
4

1 に答える 1

1

したがって、テキスト関数には多くの副作用があります。つまり、多くのものに触れ、時には戻ったり、時には標準出力に印刷したりします。デバッグ、単体テスト、リファクタリングが難しいため、これは通常は適切ではありません。

オプション2を使用します。両方のクラスを1つにマージします。言語は初期化されたときに検出され、必要に応じてメソッドが呼び出されます。

これを実装する方法は次のとおりです(OOPに関して何が変更されたかを理解できるように、できるだけ多くのコードをそのまま保持しました。変更することは他にもたくさんあります。ほとんどの場合、他の人がすでにコメントしていることと、内部から何も印刷しないことです。メソッド。メソッドが何かを返し、アプリケーションの状態を内部から変更しないようにすることをお勧めします。

私が変更したもの:

テキスト関数は、2つのグローバル変数($ Url)と(実際には言語オブジェクトからの$ Lang)を使用して、特定の時間にグローバル変数($ Banner)を実際に変更し、データベースからIDを返すか、場合によっては標準に出力していました。出力。

text関数をLanguageクラスに移動したので、Languageクラスのインスタンス変数$Langを使用するようにグローバル$Lang変数を変換しました

$ Urlメソッドはテキスト関数でのみ使用されているため、テキストメソッドに渡すことができます

グローバル変数$Bannerは、実際にはテキスト関数によって設定されていますが、これは悪い副作用だと思います。私はこのコードを置き換えることにしました:

$ Banner="翻訳ミスがある可能性があります。必要に応じて報告してください。";

falseを返します。

このように、textメソッドがfalseを返した場合、$Banner変数を「誤訳がある可能性があります。必要に応じて報告してください」に設定できます。これは、オブジェクトの外部から実行されます。

また、関数内で使用されなかったため、テキスト関数からグローバル変数$Versionを削除しました

また、textメソッドを返すだけで、標準出力に出力しないようにすることをお勧めします。誤訳のスペルが間違っています。誤訳のはずです。

これがお役に立てば幸いです...

<?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;
            }
        }
    }

}

?>
于 2012-09-01T14:42:01.547 に答える