在php中调用其他类的对象?

在php中调用其他类的对象?

问题描述:

I am working on a website with php/mysql.

I have 3 files config.php, utils.php and member.php. code of the files are as below,

config.php - $objPath->docrootlibs is fine, I am sure there is no problem with this.

    /* Other library files & their object */
    require($objPath->docrootlibs.'/utils.php');
    $objUtils = new utils();

    require($objPath->docrootlibs.'/member.php');
    $objMember = new member();

utils.php

    class utils{
        function getCurrentDateTimeForMySQL(){
            return date("Y-m-d H:i:s");
        }
    }

members.php

    class member{
        var $userid;
        var $username;

        function __construct(){
            $this->lastactivity = $objUtils->getCurrentDateTimeForMySQL();
        }
    }

Now when I am including the config.php inside a page home.php with simple php include statement and running that page then it gives me following error.

Notice: Undefined variable: objUtils in D:\wamp\www\site\libs\member.php on line 17

Fatal error: Call to a member function getCurrentDateTimeForMySQL() on a non-object in D:\wamp\www\site\libs\member.php on line 17

Line numbers in error above are different, I just copied the specific part from the code here.

I am not understanding why its giving error, because objects of utils class is defined on config page before including the member class. It should detect that object.

Please check and help me to understand and correct this error.

Thanks!

我正在使用php / mysql工作。 p>

我有3个文件 config.php code>, utils.php code>和 member.php code>。 文件的代码如下, p>

config.php - $ objPath-> docrootlibs code>很好,我相信这没有问题。

  / *其他库文件& 他们的对象* / 
 n require($ objPath-> docrootlibs。'/ utils.php'); 
 $ objUtils = new utils(); 
 
 require($ objPath-> docrootlibs。'/ member。  php'); 
 $ objMember = new member(); 
  code>  pre> 
 
 

utils.php p>

  class utils  {
 function getCurrentDateTimeForMySQL(){
 return date(“Ymd H:i:s”); 
} 
} 
  code>  pre> 
 
 

members.php

 类成员{
 var $ userid; 
 var $ username; 
 
 function __construct(){
 $ this-> lastactivity = $ objUtils-&gt  ; getCurrentDateTimeForMySQL(); 
} 
} 
  code>  pre> 
 
 

现在当我在页面中包含 config.php code>时 home.php code>使用简单的php include语句并运行该页面然后它会给我以下错误。 p>

 注意:未定义的变量:D:\ wamp \ www中的objUtils 第17行\ site \ libs \ member.php 
 
发生错误:在非对象上调用成员函数getCurrentDateTimeForMySQL() 第17行的D:\ wamp \ www \ site \ libs \ member.php 
  code>  pre> 
 
 

上面错误的行号不同,我只是从中复制了特定的部分 代码在这里。 p>

我不明白它给出错误的原因,因为在包含成员类之前,在配置页面上定义了utils类的对象。 它应该检测到该对象。 p>

请检查并帮助我理解并纠正此错误。 p>

谢谢! p> div>

One Solution

Unlike JavaScript PHP will not bubble up through scopes, which means

    public function __construct(){
        $this->lastactivity = $objUtils->getCurrentDateTimeForMySQL();
    }

does not know what $objUtils is, because there is no such object defined in the local scope. This means, you have to make the object available inside that scope. The cleanest and most maintainable way to do that is to inject the utils instance to the member instance, e.g.

    public function __construct($utils){
        $this->lastactivity = $utils->getCurrentDateTimeForMySQL();
    }

However, since you seem to be using that value on construction only anyway, there is no reason why your member instance has to know how to use the utils object. So why not just insert the actual value right from the start, e.g.

    public function __construct($lastActivity){
        $this->lastactivity = $lastActivity;
    }

    // then do
    $utils  = new utils();
    $member = new member($utils->getCurrentDateTimeForMySQL());

On globals

You definitely do not want to use the global keyword or static methods. Both couple back to the global scope. This means you can no longer use the member class without the global scope. This makes maintaining, reusing, refactoring and testing harder. OOP is about encapsulation and by reaching out from the class to the global scope you are breaking that encapsulation. Use Dependency Injection as shown above instead.

Apart from that, using globals will also make your code harder to read. A developer looking at the ctor signature of member is likely to assume there is nothing else to do than just call new member. That's a lie, because she also has to setup the utils instance. In other words, you are hiding dependencies. The developer has to look at the actual code to understand what's going on. Thus, make dependencies explicit.

Some more resources:


EDITs after comments

If you really need that utils object, inject the instance and assign it to a property inside the member instance in the ctor. Then you can access it with $this->utils->foo() from anywhere else inside the member instance.

However, Utility classes are almost always a sign of bad design. It is much more likely that they should be broken apart and divided into/onto other objects. Try to find out the reponsibilities. Maybe Member should not use Utils, but Utils should be something else that uses Members.

Out of curiosity, why do you need a utility method for MySql anyway? If you use a Timestamp column in MySql for lastActivity, it will automatically update whenever the row is updated. I am assuming you are setting the lastActivity and then store the member data?

Regarding performance: you should not bother about performance. Write readable and maintainable code first and foremost. If you think your performance is not good enough, profile the application with XDebug to see what is really making an impact.

It sounds like config.php is in the global scope. You need to use the global keyword when using $objUtils

    function __construct(){
        global $objUtils;
        $this->lastactivity = $objUtils->getCurrentDateTimeForMySQL();
    }

Since your getCurrentDateForMySQL doesn't depend on anything else inside your utils object, why not make it a static function? That way you can turn your member() method into:

function __construct(){
    $this->lastactivity = utils::getCurrentDateTimeForMySQL();
}

As another comment states, use dependency injection. Insert the utilities object into the constructor. Do not introduce variables over the global scope, especially between different files. This gets very confusing and creates a mandatory order of some file includes.

class member {
   ...
   public function __construct(utils $objUtils) {
      $this->objUtils = $objUtils;
      ...
   }
}

In calling code:

$member = new member(new utils);

As an aside, I find it humorous that you have a macro with a name that is longer than the operation it performs.

As another aside, do you need a utilities class? Can the utilities just be functions?