简体   繁体   English

PHP-从另一个类调用一个类函数

[英]PHP - Calling a class function from another class

I am trying to create an error handling class that can be called from other classes, however when I call a function within the error handling class from another class, I get the following error: 我试图创建一个可以从其他类调用的错误处理类,但是当我从另一个类的错误处理类中调用一个函数时,出现以下错误:

Fatal error: Call to a member function fetch_error_text() on null in (filepath_here) on line 361 致命错误:在第361行的(filepath_here)中的null上调用成员函数fetch_error_text()

Here is the code I have so far: 这是我到目前为止的代码:

global $errhandle_func_call;    
class ERR_HANDLE
{
   public function __construct()
   {
   }

   public function fetch_error_text($err_text)
   {
       $err_text_display = $return_msg[$err_text];
       return "<h4>" . $err_text_display . "</h4>";
   }
}

$errhandle_func_call = new ERR_HANDLE();

class BASKET
{
    public function view_basket()
    {
        //some_code_here
        if($query->num_rows < 1)
        {
            echo $errhandle_func_call->fetch_error_text("basket_empty");
        }
    }
}

Thanks. 谢谢。

I do NOT recommend using globals...but this should fix it... global needs to be in EVERY function that uses it. 我不建议使用全局变量...但这应该可以解决... global变量必须位于使用它的每个函数中。 Looks like you also need global for your $return_msg . 看起来你还需要global为您$return_msg

global $errhandle_func_call;    
class ERR_HANDLE
{
   public function __construct()
   {
   }

   public function fetch_error_text($err_text)
   {
       global $return_msg;
       $err_text_display = $return_msg[$err_text];
       return "<h4>" . $err_text_display . "</h4>";
   }
}

$errhandle_func_call = new ERR_HANDLE();

class BASKET
{
    public function view_basket()
    {
        global $errhandle_func_call;
        //some_code_here
        if($query->num_rows < 1)
        {
            echo $errhandle_func_call->fetch_error_text("basket_empty");
        }
    }
}

[UPDATE 2015-04-29] Just for the heck of it, a quick, crude, introduction to my recommendations...from Easiest to Hardest...I'm also going to change your casing as ALL_UPPERCASE is usually used to denote constants and I'm a bit OCD. [UPDATE 2015-04-29]简而言之,快速,粗略地介绍我的建议...从最简单到最困难...我也将更改您的大小写,因为ALL_UPPERCASE通常用于表示常量,我有点强迫症。

Static Error Class: 静态错误类别:

class ErrorType {
    const UserError     = 1;
    const NotFoundError = 2;

    public static function getMessage( $messageId ) {
        switch( $messageId ) {
            case self::UserError: return "user error";
            case self::NotFoundError: return "not found error";
        }
    }
}
class ErrorHandler {
    public static function fetchErrorText( $errorType) {
        return "<h4>".ErrorType::getMessage($errorType)."</h4>";
    }
}

ErrorHandler::fetchErrorText( ErrorType::UserError );

This is definitely the easiest and gets you away from globals. 这绝对是最简单的方法,可让您远离全局。 I added the ErrorType class to reduce the "magic strings" in your code by giving you constant values to pass into the function. 我添加了ErrorType类,通过为您提供常量值以传递到函数中来减少代码中的“魔术字符串”。 This will help to avoid typos, etc., as your IDE can give you intellisense for it. 这将有助于避免输入错误,因为您的IDE可以为您提供智能感知。

However, static classes are not friendly to Unit Tests. 但是,静态类对单元测试不友好。 So, that's where "Inversion of Dependency" can come into play. 因此,这就是“依赖反转”可以发挥作用的地方。 The easiest way to invert your dependencies is a Service Locator because you don't have to be able to modify your constructor to be able to pass in an instance of an object. 反转依赖关系的最简单方法是服务定位器,因为您不必修改构造函数就可以传递对象的实例。 Some consider this an anti-pattern, but it's extremely useful in the right situations (eg Convention over Configuration, etc.). 有人认为这是一种反模式,但是在正确的情况下(例如,约定优于配置等)非常有用。

Inversion of Dependency: Service Locator 依赖倒置:服务定位器

//first thing you need for inversion is an interface
interface IHandleError {
    public function getErrorMessage( $errorType );
}

//imaginary ServiceLocator class, defining instance of interface to use
ServiceLocator::define( array(
    'IHandleError' => 'SomeNamespace\ErrorHandler'
) );

class Basket {
    public function viewBasket() {
        //grab it when you need it
        $errorHandler = ServiceLocator::get('IHandleError');
        if( query->num_rows < 1 ) {
            echo $errorHandler->getErrorMessage( ErrorType::BasketEmpty );
        }
    }
}

The ServiceLocator object is imaginary...but in its simplest form it's just an array of key => value, where the value points to a class...and the ::get() method instantiates an instance or singleton of the class. ServiceLocator对象是虚构的...但是以最简单的形式,它只是一个键=> value的数组,其中值指向一个类...,而:: get()方法实例化该类的实例或单例。 I'm doing more "magic strings" here, but didn't want to make it too convoluted. 我在这里做更多的“魔术弦”,但不想让它太复杂。

Inversion of Dependency: Dependency Injection 依赖倒置:依赖注入

Dependency Injection, on the other hand, is simpler than the ServiceLocator in concept...but sometimes harder in implementation because you need access to modify the constructor of the class and be able to modify its instantiations to pass in the object. 另一方面,从概念上讲,依赖注入比ServiceLocator更简单...但是有时在实现上会更困难,因为您需要访问以修改类的构造函数并能够修改其实例以传递给对象。

class Basket {
    private $_errorHandler;
    public function __construct( IHandleError $errorHandler ) {
        $this->_errorHandler = $errorHandler;
    }
}

$basket = new Basket( $errorHandler );

Any of these 3 will steer you away from globals and improve the maintainability of your code a bit. 这3种方法中的任何一种都会使您远离全局变量,并稍微提高代码的可维护性。

Why not use heritage ? 为什么不使用遗产? Your class BASKET can extends from ERR_HANDLE : 您的班级BASKET可以从ERR_HANDLE扩展:

class BASKET  extends ERR_HANDLE { 
      public function view_basket() {
          //some_code_here 
          if($query->num_rows < 1) { 
                  echo parent::fetch_error_text("basket_empty"); 
          } 
      }  
   }

Dependency Injection (DI) Is Easy 依赖注入(DI)很容易

Depending on weather your class requires a dependency or if it is optional depends on how you 'inject' it. 根据天气的不同,您的课程需要依赖项,或者它是否可选,取决于您如何“注入”它。 Note that a 'dependence' could be either an object (an instantiated class) or a property (a class member variable). 请注意,“依赖项”可以是对象(实例化的类)或属性 (类成员变量)。

As it looks, your 'BASKET' class requires the 'ERR_HANDLE" class for it to work correctly thus it would be 'best practice' for you to use 'constructor injection'. Constructor injection mean 'injecting' it into the 'construct' method of the class. 看起来,您的“ BASKET”类需要 “ ERR_HANDLE”类才能正常工作,因此使用“构造函数注入”是“最佳实践”。构造函数注入意味着将其“注入”到“ construct”方法中班上的

This (dependency injection) allows for separation of concerns amongst many, many other things. 这种(依赖注入)可以将许多其他问题分开。

ErrorHandle.php ErrorHandle.php

<?php

class ERR_HANDLE
{
    public function fetch_error_text($err_text)
    {
        $err_text_display = $return_msg[$err_text];
        return "<h4>" . $err_text_display . "</h4>";
    }
}

Basket.php Basket.php

<?php

class BASKET
{
    private $err_handle;

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

    public function view_basket()
    {
        //some_code_here

        if($query->num_rows < 1)
        {
            // The next line is where you use the injected objects method.
            return $this->err_handle->fetch_error_text("basket_empty");
        }
    }
}

Then The Actual Injection 然后实际注射

<?php

// Instantiate the error handle class.
$err_handle = new ERR_HANDLE();

// Whilst instantiating the BASKET class, inject the ERR_HANDLE object.
$basket = new Basket($err_handle);

// View the basket.
echo $basket->view_basket();

Now, the final problem you should be able to solve is how to get the variable '$return_msg' into your 'ERR_HANDLE' class. 现在,您应该能够解决的最后一个问题是如何将变量“ $ return_msg”放入您的“ ERR_HANDLE”类。 PS: Inject it. PS:注入它。

I recommend reading up on namespaces , becoming more familiar with classes and objects and reading about dependency injection. 我建议阅读命名空间 ,对类和对象更加熟悉,并阅读有关依赖项注入的知识。

Never stop learning... 从未停止学习...

Doesn't look like you're actually instantiating an instance of the ERR_HANDLE inside the scope you're trying to run its member function from. 看起来您实际上不是在尝试从中运行ERR_HANDLE实例的作用域内实例化该实例。

$errhandle_func_call is being created outside of the BASKET class scope, but that object needs to be available within that public function of the BASKET class $ errhandle_func_call是在BASKET类范围之外创建的,但是该对象需要在BASKET类的公共函数中可​​用

you can use a autoload file to load all the ".class.php" file inside a directory by using this code. 您可以使用自动加载文件,通过使用此代码来加载目录内的所有“ .class.php”文件。

<?
    function __autoload($classname)
    {
        require_once(strtolower($classname).'.class.php');
    }
        $first_class = new first_class();
        $second_class = new second_class();

    ?>

so you put all the class file in the same directory that this file. 因此,您将所有类文件放在与此文件相同的目录中。 and you just include this file in all the page where you want to use any class 并且您只需将此文件包含在要使用任何类的所有页面中

You can do this another way. 您可以使用另一种方法。

<?php

class error {

    public function hes_dead() {
        // deal with error
    }

}

class needs_error_class {

    private $err;
    public function __construct() {

        // This is called dependency injection.
        $this->err = new Error;

    }

    public function some_function() {

        // need that error handing now
        $this->err->hes_dead();
    }
}

Alternatively you can try this way to call your class. 另外,您可以尝试这种方式来调用您的课程。

class ERR_HANDLE
{
   public function empty_basket_error_text($err_text)
   {
       return "<h4>".$err_text."</h4>";
   }
}
class BASKET
{
    public function view_basket()
    {
        //some_code_here
        //if($query->num_rows < 1)
        // {
            $this->errhandle = new ERR_HANDLE();
            return $this->errhandle->empty_basket_error_text("Empty basket");
        // }
    }
}
$basket = new BASKET();
echo $basket->view_basket();

http://3v4l.org/U2fsH http://3v4l.org/U2fsH

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM