2014-09-30 85 views
0

我想从一个单独的文件添加功能到类,我不知道这是可能的!从另一个文件分配功能到一个类

$mClass = new MyClass(); 
$mClass->new_Functions[0](10); // Is there a way to have it in this form? 

class myClass 
{ 
    private $Pvar = 5; 
    $new_Fcuntions; 
    function __construct() 
    { 
     include('additional.functions.php'); 
     $arr = get_defined_functions(); 
     $this->new_Functions = $arr['user']; 
     // trying to call the function with parameter 10 
     call_user_func(array($this, $this->new_Functions[0]), 10); 
    } 

} 

[additional.functions.php]文件

function operate($y) 
{ 
    return $this->Pvar * $y; 
} 

-----编辑-------因为它是不明确! “additional.functions.php”是一个模块,将会有多个模块添加到应用程序中,并且每个模块都可能具有多个功能,并且模块可以互相调用!

additional.functions.php [模块文件]

function operate($y) 
{ 
    return $this->Pvar * $y; 
} 

function do-more($foo) 
{ 
    return $this->operate(20) + $foo; 
} 

another.functions.php [另一模块]

function do-another($foo) 
{ 
    return $this->do-more(30) - $foo; 
} 

function add($foo, $bar) 
{ 
    return $foo + $bar; 
} 

欣赏每一个参与,它已经有一段时间我试图操纵与它在一起! 这是可能的,还是应该放弃!

+0

该函数只能在类内部工作,所以可能需要创建一个函数类,以便其他类可以扩展。 – AbraCadaver 2014-09-30 19:42:43

+4

这是一个非常奇怪的方法,实质上是类继承。我建议你简单地使用包含你的函数的子类来扩展你的当前类。 – 2014-09-30 19:42:58

回答

1

它看起来像我正在寻找Traits,这是PHP 5.4.0以来的新功能。使用特征,你可以将代码片段“混合”到其他类中,这个概念被称为“水平重用”。

如果你不是在寻找特性,你可以用Runkit做你想做的事情,但是我建议尽可能远离它,如果你不是真的对PHP内部感兴趣的话。

在任何情况下,无论你正在试图做的是非常有趣

+0

我从来没有尝试过那些有趣的内容,但USE可以在类__construct中使用! – meYnot 2014-09-30 20:04:22

0

如果你可以在该文件中,而不是与功能 文件的另一个类 - 最佳的解决方案将是性状 http://php.net/manual/en/language.oop5.traits.php 或使用继承

如果你的代码移动到类,你能避免很多不必要的代码。我的意思是:

include('additional.functions.php'); 
$arr = get_defined_functions(); 
$this->new_Functions = $arr['user']; 
// trying to call the function with parameter 10 
call_user_func(array($this, $this->new_Functions[0]), 10); 

这将是例如为:

class myClass extends MyBaseClassWithMyAwesomeFunctions 
{ 
    private $Pvar = 5; 
} 
+0

感谢您的回答,但我有许多未知文件将其函数添加到myClass。 – meYnot 2014-09-30 19:58:22

1

我得到了它与依赖注入工作。 pvar必须是公共的,或者创建一个__get方法来返回私有变量。我还使用了函数名,因为它似乎吸尘器我通过名称来使用它,而不是它在列表中的位置,但如果你想保住你的,然后只是把$key在那里你看到$value从线路:$this->function_list[$value] = ...

function operate($y, $that) 
{ 
    return $that->Pvar * $y; 
} 

class Example { 

    public $function_list = array(); 
    private $Pvar = 5; 
    public function __construct() 
    { 
     $list = get_defined_functions(); 
     $that = $this; 
     foreach ($list['user'] as $key => $value) { 
      $this->function_list[$value] = function() use ($value, $that) { 
       print call_user_func_array($value, array_merge(func_get_args(), array($that))); 
      }; 
     } 
    } 
    public function __get($key) 
    { 
     if (isSet($this->$key)) { 
      return $this->$key; 
     } else { 
      throw new \Exception('Key "'.$key.'" does not exist'); 
     } 
    } 
} 

$Ex = new Example(); 

$Ex->function_list['operate'](10); 
0

也许这种方法可以帮助你:

与附加功能的文件,没有定义命名的功能,但返回封闭,即希望(至少)对象(的MyClass实例)作为参数:

<?php 

// additional.functions.php 

return function ($myObject) { 
    $Object->multiplyPvar($myObject->getTheNumber()); 
    $Object->doSomethingElse(42, 'foo'); 
}; 

客户需求,建立MyClass收集从文件的功能集成到阵列:

<?php 

$files = [ 
    '/path/to/my/additional.functions1.php', 
    '/path/to/my/additional.functions2.php' 
]; 

$initFunctions = []; 
foreach ($files as $path) 
    $initFunctions[] = include $path; 

$MyObject = new \MyClass($initFunctions); 

构造函数,然后调用这些函数:

<?php 

class MyClass 
{ 
    public function __construct(array $additionalInitFunctions) 
    { 
     foreach ($additionalInitFunctions as $additionalInitFunction) 
      $additionalInitializerFunction($this); // you can also add parameters of course 
    } 
} 

这样的类保存也可测试以及函数文件。也许这可以以任何方式帮助你。你永远不应该考虑直接从类之外的任何代码修改对象的内部(私有)状态。这是不可测试的!考虑在实现代码之前编写测试(称为“测试驱动开发”)。你会看到,如果允许该类以外的任何代码修改类实例的内部(私有)状态,则不可能测试该类。而你不想拥有这个。如果你改变了你的课堂上的一些内部实现细节而又没有打破该课程的单元测试,那么你可能会破坏你的任何additional.functions.php文件中的一些代码,并且没有测试会告诉你:“嘿:你现在破坏了一些东西” 。

+0

谢谢@stofl,这个假定additional.functions.php是一个单一的函数。 – meYnot 2014-10-01 00:26:54

+0

让你的模块文件返回一个闭包数组。或者更好:编写一个Module类,它期望它应该初始化或修改为构造函数参数的对象。您可以为模块提供一个名称空间,例如'\ modules \ MyModuleA'。然后你可以在这个命名空间中创建一个'Init'类。它的构造函数会期望一个'MyClass'的实例作为参数,并会调用所有修改$ MyObject的私有方法。你可以为你的'MyClass'编写一个工厂,它需要一个模块名称列表作为参数:'public function buildMyClass(array $ moduleNames)'...... – stofl 2014-10-01 05:34:33

+0

或者依赖注入可能会帮助你。您可以像这样定义构造函数参数(模块init类的参数):'__construct($ ServiceA,$ ServiceB,$ ServiceC)'。一个模块加载器对象会通过[reflection](http://php.net/manual/en/book.reflection.php)读取参数的名称,并传入所需的服务。这样,每个模块都可以操作(或初始化)主应用程序的不同组件(服务)。有很多种方法来做这种事情。重要的是:你如何测试它。你怎么能以某种方式设计它,它是可测试的。 – stofl 2014-10-01 05:41:29

1

如果你想从你的模块扩展MyClass(而不是对其进行初始化,就像在你的示例代码),比你能做到这一点在这样一个办法:

<?php 

namespace modules\MyModuleA; 

class MyClassExtension 
{ 
    private $MyObject; 

    public function __construct(\MyClass $MyObject) 
    { 
     $this->MyObject = $MyObject; 
    } 

    public function doSomething($anyParameter) 
    { 
     return $this->MyObject->doSomethingElse($anyParameter * 5, 42, 'foo'); 
    } 
} 

而且MyClass

<?php 

class MyClass extends \Extensible 
{ 
    // some code 
} 

abstract class Extensible 
{ 
    private $extensions = []; 

    public function extend($extension) 
    { 
     $this->extensions[] = $extension; 
    } 

    public function __call($methodName, $parameters) 
    { 
     foreach ($this->extensions as $Extension) { 
      if (in_array($methodName, get_class_methods($Extension)) 
       return call_user_func_array([$Extension, $methodName], $parameters); 
     } 
     throw new \Exception('Call to undefined method ' . $methodName . '...'); 
    } 

    public function hasExtension($extensionName) 
    { 
     return in_array($this->extensions, $extensionName); 
    } 
} 

而且把它放在一起:

<?php 

$moduleNames = ['MyModuleA', 'MyModuleB']; 

$MyObject = new \MyClass; 

foreach ($moduleNames as $moduleName) { 
    $className = '\\modules\\' . $moduleName . '\\MyClassExtension'; 
    $module = new $className($MyObject); 
    $MyObject->extend($module); 
} 

// Now you can call a method, that has been added by MyModuleA: 

$MyObject->doSomething(10); 

您应该添加当然扩展类的接口...

问题是:如果您的应用程序中的任何代码调用$MyObject的方法,那么会发生什么情况,因为该模块尚未加载。你总是必须检查if ($MyObject->hasExtension('ModuleA')) { ... },但是,当然,应用程序不应该知道任何模块。所以我不会以这种方式设计应用程序。

相关问题