php依赖注入对象传参问题,php传参类型声明(type declaration)及常见的依赖注入(dependency injection)...

该篇属于《Laravel底层核心技术实战揭秘》这一课程《laravel底层核心概念解析》这一章的扩展阅读。由于要真正学好laravel底层,有些PHP相关的知识必须得了解,考虑到学员们的基础差异,为了避免视频当中过于详细而连篇累牍,故将一些laravel底层实现相关的PHP知识点以文章形式呈现,供大家预习和随时查阅。

php传参类型声明(type declaration)

今天,我们不在laravel里,自己搞个PHP文件测试:

class Bar {}

function injection($bar)

{

var_dump($bar);

}

injection();

?>

我们想的是把Class Bar的一个实例传进去,但是这样肯定会报错:

Fatal error: Uncaught ArgumentCountError: Too few arguments to function injection(), 0 passed in

好吧,那就给你传个参数进去:

$bar = new Bar;

injection($bar);

这样就可以了:

object(Bar)[1]

问题是,这个时候,我怎么确保你传递进去的就是Class Bar的实例呢?我们完全可以传个别的进去啊:

class Foo {}

$bar = new Foo;

injection($bar);

这个时候也不会报错:

object(Foo)[1]

由于这个时候我们的function injection($bar)期望传入的只是一个变量$bar,所以如果我们需要根据这个变量$bar的类型来操作,我们就得这样:

class Bar {}

class Foo {}

function injection($bar)

{

if($bar instanceof Bar){

echo 'Bar type';

}elseif($bar instanceof Foo){

echo 'Foo type';

}

}

$bar = new Foo;

injection($bar);

?>

这样的话就会输出:

Foo type

看到这儿,相信你应该能想起我们在《Laravel底层核心技术实战揭秘》自定义常见的系统Exception时用过:

public function render($request, Exception $e)

{

if($e instanceof TokenMismatchException){

...

}

if($e instanceof ModelNotFoundException){

...

}

if($e instanceof FatalErrorException){

...

}

...

}

但是,更经常的是,我们在往一个方法里传参的时候,我们只期望是某一种类型(type),比如你传进来的必须是一个UserModel的实例,传其他的进来就没有意义,这个时候就需要用到PHP的类型声明(type declaration),允许函数在调用时要求参数为特定类型。 如果给出的值类型不对,那么将会产生一个错误: 在PHP 5中,这将是一个可恢复的致命错误,而在PHP 7中将会抛出一个TypeError异常。

好吧,这没什么稀奇的,相信很多人都已经知道了,所以之前的例子现在就可以写成:

class Bar {}

class Foo {}

function injection(Bar $bar)

{

echo get_class($bar);

}

$bar = new Foo;

injection($bar);

?>

此时就会输出:

Fatal error: Uncaught TypeError: Argument 1 passed to injection() must be an instance of Bar, instance of Foo given,

如果我们将$bar = new Foo;改成$bar = new Bar;就会输出:

Bar

这样我们就限定了依赖注入(dependency injection)的类型(type hinted),嗯,没啥高科技。

常见的依赖注入(dependency injection)——方法注入(method injection)

这里需要注意的是,我们在执行injection($bar);前,手动实例化了一个BarClass,所以这个时候相当于我们执行的是:injection(new Bar);,如果这个injection()方法是在一个class当中,因为这样更符合实际情况,例如:

class Bar {}

class Foo {}

class Baz {

function injection(Bar $bar)

{

echo get_class($bar);

}

}

$baz = new Baz;

$bar = new Bar;

$result = $baz->injection($bar);

//相当于$result = (new Baz)->injection(new Bar);

?>

这就是一个(单一)方法注入(method injection)。

常见的依赖注入(dependency injection)——构造函数依赖注入(constructor injection)

如果这个object参数还经常用在其他同类(class)方法里,那么我们通常放在一个构造函数(constructor)里,就成了这样子:

class Baz {

protected $bar;

public function __construct(Bar $bar)

{

$this->bar = $bar;

}

public function check()

{

echo get_class($this->bar);

}

}

这个时候我们就不能直接$baz = new Baz;了,得是这样调用:

$baz = new Baz(new Bar);

$result = $baz->check();

看上去没错,挺简单,这就是构造函数依赖注入(constructor injection),这些我们laravel实战优雅入门:任务管理系统(一)都讲烂了。

层层依赖的问题

但如果Class Bar还有它自己的依赖呢?比如说:

class Foo {}

class Bar {

protected $foo;

public function __construct(Foo $foo)

{

$this->foo = $foo;

}

}

稍微复杂点的类有几个依赖很正常,那么现在我们的调用就得这样了:

$baz = new Baz(new Bar(new Foo));

$result = $baz->check();

看出问题来了吗?也就是说现在我们还只是个简单的示例,实际当中,当你的依赖逐渐增多,这个class依赖那个,那个又依赖另一个的时候,层层依赖,稍微大点的系统很常见的事儿。

但是如果我们每次实例化一个对象,就得手动去传递或者说注入一大堆依赖,就得不断地去new来new去,那还了得?

如何自动地去引入相应地依赖,不论我们的依赖有多少层?

或者说,Laravel能不能做到这一点呢?都说Laravel IOC Container,又称Service Container(服务容器),很强大,那么是否强大到自动给我们构建依赖呢?

限于篇幅,我们下一节讲~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用 Python 的 ast 模块来过滤 javalang.tree.MethodDeclaration 和 javalang.tree.ClassDeclaration。 具体实现可以参考下面的代码: ```python import javalang import ast class JavaNodeVisitor(ast.NodeVisitor): def __init__(self): self.class_nodes = [] self.method_nodes = [] def visit_ClassDeclaration(self, node): self.class_nodes.append(node) def visit_MethodDeclaration(self, node): self.method_nodes.append(node) def filter_java_nodes(java_code): tree = javalang.parse.parse(java_code) visitor = JavaNodeVisitor() visitor.visit(tree) return visitor.class_nodes, visitor.method_nodes ``` 使用示例: ```python java_code = """ public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World"); } } """ class_nodes, method_nodes = filter_java_nodes(java_code) print(class_nodes) print(method_nodes) ``` 输出结果: ``` [ClassDeclaration(modifiers=[], name='HelloWorld', extends=None, implements=[], body=[MethodDeclaration(modifiers=[public, static], type=VoidType(), name='main', parameters=[FormalParameter(modifiers=[], type=ArrayType(qualified_name='java.lang.String'), variable_declarator_id=VariableDeclaratorId(), position=<Position line=2, column=33>)], throws=[], body=Block(statements=[ExpressionStatement(expression=MethodInvocation(select=FieldAccess(target=Name(qualifier=None, identifier='System', position=<Position line=3, column=9>), name='out', position=<Position line=3, column=15>), member='println', arguments=[StringLiteral(value='Hello, World', position=<Position line=3, column=21>)], position=<Position line=3, column=8>), position=<Position line=3, column=8>)], position=<Position line=2, column=38>), position=<Position line=2, column=9>)], position=<Position line=1, column=1>)], position=<Position line=1, column=1>)] [MethodDeclaration(modifiers=[public, static], type=VoidType(), name='main', parameters=[FormalParameter(modifiers=[], type=ArrayType(qualified_name='java.lang.String'), variable_declarator_id=VariableDeclaratorId(), position=<Position line=2, column=33>)], throws=[], body=Block(statements=[ExpressionStatement(expression=MethodInvocation(select=FieldAccess(target=Name(qualifier=None, identifier='System', position=<Position line=3, column=9>), name='out', position=<Position line=3, column=15>), member='println', arguments=[StringLiteral(value='Hello, World', position=<Position line=3, column=21>)], position=<Position line=3, column=8>), position=<Position line=3, column=8>)], position=<Position line=2, column=38>), position=<Position line=2, column=9>)] ``` 可以看到,我们成功地过滤出了 Java 代码中的和方法节点,并返回了它们的列表。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值