文档章节

Laravel5.3之PHP反射(Reflection) (上)

botkenni
 botkenni
发布于 2016/11/07 09:22
字数 2230
阅读 35
收藏 1

说明:Laravel中经常使用PHP的反射特性来设计代码,本文主要学习PHP的反射特性,来提高写代码时的设计质量。PHP提供一套检测class, interface, trait, property, method的两个工具包:Introspection FunctionsReflection API,类似于探针一样的东西来探测这些一等公民。本文先看下Introspection Functions的使用。

开发环境: Laravel5.3 + PHP7

Introspection Functions

Introspection Functions是用来操作object class的一些函数,PHP提供了大量的Introspection Functions来操作class, interface, trait, method, property:

  1. class_exists()

  2. interface_exists()

  3. method_exists()

  4. property_exists()

  5. trait_exists()

  6. class_alias()

  7. get_class()

  8. get_parent_class()

  9. get_called_class()

  10. get_class_methods()

  11. get_class_vars()

  12. get_object_vars()

  13. is_subclass_of()

  14. is_a()

class_exists()

Laravel源码中好多个地方使用到class_exists()方法来判断指定类是否存在,如\Illuminate\Database\Connection::isDoctrineAvailable()的源码:

    public function isDoctrineAvailable()
    {
        return class_exists('Doctrine\DBAL\Connection'); // Doctrine\DBAL\Connection::class类是否存在,大小写不敏感
    }

写个PHPUnit测试下(爆绿灯,说明是正确的,这里不截图了。后面所有Introspection的测试都放在IntrospectionTest这个单元测试里):

namespace MyRightCapital\Container\Tests;

class IntrospectionTest extends \PHPUnit_Framework_TestCase
{
    public function testClassExists()
    {
        // Arrange
        
        // Actual
        $class_exists = class_exists(TestClassExists::class);
        // Assert
        $this->assertTrue($class_exists);
    }
}

class TestClassExists
{
    
}

interface_exists()

interface_exists()是用来检查接口是否存在,写个PHPUnit测试下,爆绿灯:

namespace MyRightCapital\Container\Tests;

class IntrospectionTest extends \PHPUnit_Framework_TestCase
{
    public function testInterfaceExists()
    {
        // Arrange
        
        // Actual
        $interface_exists = interface_exists(TestInterfaceExists::class);
        // Assert
        $this->assertTrue($interface_exists);
    }
}

interface TestInterfaceExists
{
    
}

method_exists()

检查类的方法(private,protected,public)是否存在于指定的类对象或类名中,Laravel中很多处用到了这个函数,如Application中的register()检查service provider中register是否存在,和bootProvider()中检查service provider中boot()方法是否存在:

public function register($provider, $options = [], $force = false)
{
    ...
    
    if (method_exists($provider, 'register')) {
            $provider->register();
    }
    
    ...
}
protected function bootProvider(ServiceProvider $provider)
{
    if (method_exists($provider, 'boot')) {
        return $this->call([$provider, 'boot']);
    }
}

这里写个PHPUnit测试下,爆绿灯:

    public function testMethodExists()
    {
        // Arrange
        $test_class_exists = new TestClassExists();
        
        // Actual
        $object_method_exists1    = method_exists($test_class_exists, 'testPrivateMethodExists');
        $object_method_exists2    = method_exists($test_class_exists, 'testProtectedMethodExists');
        $object_method_exists3    = method_exists($test_class_exists, 'testPublicMethodExists');
        $classname_method_exists1 = method_exists(TestClassExists::class, 'testPrivateMethodExists');
        $classname_method_exists2 = method_exists(TestClassExists::class, 'testProtectedMethodExists');
        $classname_method_exists3 = method_exists(TestClassExists::class, 'testPublicMethodExists');
        
        // Assert
        $this->assertTrue($object_method_exists1);
        $this->assertTrue($object_method_exists2);
        $this->assertTrue($object_method_exists3);
        $this->assertTrue($classname_method_exists1);
        $this->assertTrue($classname_method_exists2);
        $this->assertTrue($classname_method_exists3);
    }
    
    
    class TestClassExists
    {
        private function testPrivateMethodExists()
        {
        }
        
        protected function testProtectedMethodExists()
        {
        }
        
        public function testPublicMethodExists()
        {
        }
    }

property_exists()

检查该属性(private, protected, public)是否存在于类对象或类名中,Laravel很多地方用到了该函数,如\Illuminate\Foundation\Auth\RedirectsUsers::redirectPath()源码:

    public function redirectPath()
    {
        return property_exists($this, 'redirectTo') ? $this->redirectTo : '/home';
    }

写个PHPUnit测试下该函数,爆绿灯:

    // class IntrospectionTest
    public function testPropertyExists()
    {
        // Arrange
        $test_class_exists = new TestClassExists();
        
        // Actual
        $private_property1   = property_exists($test_class_exists, 'testPrivatePropertyExists');
        $private_property2   = property_exists(TestClassExists::class, 'testPrivatePropertyExists');
        $protected_property1 = property_exists($test_class_exists, 'testProtectedPropertyExists');
        $protected_property2 = property_exists(TestClassExists::class, 'testProtectedPropertyExists');
        $public_property1    = property_exists($test_class_exists, 'testPublicPropertyExists');
        $public_property2    = property_exists(TestClassExists::class, 'testPublicPropertyExists');
        
        // Assert
        $this->assertTrue($private_property1);
        $this->assertTrue($private_property2);
        $this->assertTrue($protected_property1);
        $this->assertTrue($protected_property2);
        $this->assertTrue($public_property1);
        $this->assertTrue($public_property2);
    }
    
    
    class TestClassExists
    {
        private   $testPrivatePropertyExists;
        protected $testProtectedPropertyExists;
        public    $testPublicPropertyExists;
    }

trait_exists()

检查trait是否存在,写下PHPUnit测试,爆绿灯:

    // class IntrospectionTest
    public function testTraitExists()
    {
        // Arrange
        
        // Actual
        $test_trait_exists = trait_exists(TestTraitExists::class);
        
        // Assert
        $this->assertTrue($test_trait_exists);
    }
    
    trait TestTraitExists
    {
    
    }

class_alias()

给指定类取别名,Laravel中只有一处使用了class_alias(),用来给config/app.php中$aliases[ ]注册别名,可看下Laravel5.3之bootstrap源码解析,看下Laravel中如何使用的:

    public function load($alias)
    {
        if (isset($this->aliases[$alias])) {
            return class_alias($this->aliases[$alias], $alias);
        }
    }

写个PHPUnit测试,爆绿灯:

    public function testClassAlias()
    {
        // Arrange
        class_alias(TestClassExists::class, 'MyRightCapital\Container\Tests\AliasTestClassExists');
        $test_class_exists = new TestClassExists();
        
        // Actual
        $actual = new AliasTestClassExists();
        
        //Assert
        $this->assertInstanceOf(TestClassExists::class, $actual);
        $this->assertInstanceOf(AliasTestClassExists::class, $test_class_exists);
    }

get_class()

get_class()获取对象的类名,这个函数在Laravel中大量地方在用了,如Application::getProvider($provider)方法,是个很好用的方法:

    public function getProvider($provider)
    {
        $name = is_string($provider) ? $provider : get_class($provider);

        return Arr::first($this->serviceProviders, function ($value) use ($name) {
            return $value instanceof $name;
        });
    }

写个PHPUnit测试,爆绿灯:

    public function testGetClass()
    {
        // Arrange
        $test_class_exists = new TestClassExists();
        
        // Actual
        $class_name = get_class($test_class_exists);
        
        // Assert
        $this->assertSame(TestClassExists::class, $class_name);
    }

get_parent_class()

get_parent_class()是用来获取类的父类名,目前Laravel中还没用到这个函数,传入的可以是子类对象或者子类名,写个PHPUnit测试下:

    // namespace MyRightCapital\Container\Tests;
    // class IntrospectionTest extends \PHPUnit_Framework_TestCase
    public function testGetParentClass()
    {
        // Arrange
        $child_class = new ChildClass();
        
        // Actual
        $parent_class1 = get_parent_class($child_class);
        $parent_class2 = get_parent_class(ChildClass::class);
        
        // Assert
        $this->assertSame(ParentClass::class, $parent_class1);
        $this->assertSame(ParentClass::class, $parent_class2);
    }
    
    class ChildClass extends ParentClass 
    {
        
    }
    
    class ParentClass
    {
        
    }

get_called_class()

get_called_class()获取后期静态绑定类即实际调用类的名称,Laravel中还没使用到该函数,不妨写个测试看下如何使用:

    // namespace MyRightCapital\Container\Tests;
    // class IntrospectionTest extends \PHPUnit_Framework_TestCase
    public function testGetCalledClass()
    {
        // Arrange
        $child_class  = new ChildClass();
        $parent_class = new ParentClass();
        
        // Actual
        $child_called_class = $child_class->testGetCalledClass();
        $parent_called_class = $parent_class->testGetCalledClass();
        
        // Assert
        $this->assertSame(ChildClass::class, $child_called_class);
        $this->assertSame(ParentClass::class, $parent_called_class);
    }
    
    class ChildClass extends ParentClass
    {
        
    }
    
    class ParentClass
    {
        public function testGetCalledClass()
        {
            return get_called_class();
        }
    }

get_class_methods()

get_class_methods()用来获取类的方法名组成一个数组(测试只能是public),Laravel只有一处用到了该方法\Illuminate\Database\Eloquent\Model::cacheMutatedAttributes() :line 3397,这里写个PHPUnit测试,爆绿灯:

    public function testGetClassMethod()
    {
        // Arrange
        $get_class_methods1 = get_class_methods(ChildClass::class);
        $get_class_methods2 = get_class_methods(new ChildClass());
        
        // Actual
        
        // Assert
        $this->assertFalse(in_array('testPrivateGetClassMethod', $get_class_methods1, true));
        $this->assertFalse(in_array('testPrivateGetClassMethod', $get_class_methods2, true));
        $this->assertFalse(in_array('testProtectedGetClassMethod', $get_class_methods1, true));
        $this->assertFalse(in_array('testProtectedGetClassMethod', $get_class_methods2, true));
        $this->assertTrue(in_array('testPublicGetClassMethod', $get_class_methods1, true));
        $this->assertTrue(in_array('testPublicGetClassMethod', $get_class_methods2, true));
        $this->assertTrue(in_array('testGetCalledClass', $get_class_methods1, true));
        $this->assertTrue(in_array('testGetCalledClass', $get_class_methods2, true));
    }
    
    class ChildClass extends ParentClass
    {
        private function testPrivateGetClassMethod()
        {
        }
        
        protected function testProtectedGetClassMethod()
        {
        }
        
        public function testPublicGetClassMethod()
        {
        }
    }

get_class_vars()

get_class_vars()只会读取类的public属性组成一个数组,类似于get_class_methods(),若属性没有默认值就为null,目前Laravel中还未使用,看下PHPUnit测试:

    public function testGetClassVars()
    {
        // Arrange
        
        // Actual
        $class_vars = get_class_vars(ChildClass::class);
        
        // Assert
        $this->assertArrayNotHasKey('privateNoDefaultVar', $class_vars);
        $this->assertArrayNotHasKey('privateDefaultVar', $class_vars);
        $this->assertArrayNotHasKey('protectedNoDefaultVar', $class_vars);
        $this->assertArrayNotHasKey('protectedDefaultVar', $class_vars);
        $this->assertEmpty($class_vars['publicNoDefaultVar']);
        $this->assertEquals('public_laravel', $class_vars['publicDefaultVar']);
    }
    
    class ChildClass extends ParentClass
    {
        private   $privateNoDefaultVar;
        private   $privateDefaultVar   = 'private_laravel';
        protected $protectedNoDefaultVar;
        protected $protectedDefaultVar = 'protected_laravel';
        public    $publicNoDefaultVar;
        public    $publicDefaultVar    = 'public_laravel';
   }     

get_object_vars()

get_object_vars()只会读取对象的public属性组成一个数组,类似于get_class_vars(), get_class_methods(),且属性没有默认值就是null,Laravel中只有一处使用到\Illuminate\Mail\Jobs\HandleQueuedMessage::__sleep() :line 78,写个PHPUnit测试下,爆绿灯:

    public function testGetObjectVars()
    {
        // Arrange
        $get_object_vars = new TestGetObjectVars(1, 2, 3);
        
        // Actual
        $object_vars = get_object_vars($get_object_vars);
        
        // Assert
        $this->assertArrayNotHasKey('x', $object_vars);
        $this->assertArrayNotHasKey('y', $object_vars);
        $this->assertEquals(3, $object_vars['z']);
        $this->assertArrayNotHasKey('dot1', $object_vars);
        $this->assertArrayNotHasKey('dot2', $object_vars);
        $this->assertArrayNotHasKey('circle1', $object_vars);
        $this->assertArrayNotHasKey('circle2', $object_vars);
        $this->assertEquals(10, $object_vars['line1']);
        $this->assertEmpty($object_vars['line2']);
    }
    
    class TestGetObjectVars
    {
        private   $x;
        protected $y;
        public    $z;
        private   $dot1    = 10;
        private   $dot2;
        protected $circle1 = 20;
        protected $circle2;
        public    $line1   = 10;
        public    $line2;
        
        public function __construct($x, $y, $z)
        {
            
            $this->x = $x;
            $this->y = $y;
            $this->z = $z;
        }
    }

is_subclass_of()

is_subclass_of()用来判断给定类对象是否是另一给定类名的子类,Laravel中有用到,这里写下PHPUnit测试,爆绿灯:

    public function testIsSubclassOf()
    {
        // Arrange
        $child_class = new ChildClass();
        
        // Actual
        $is_subclass = is_subclass_of($child_class, ParentClass::class);
        
        // Assert
        $this->assertTrue($is_subclass);
    }

is_a()

is_a()用来判定给定类对象是否是另一给定类名的对象或是子类,和is_subclass_of()有点类似,只是is_a()还可以判定是不是该类的对象,is_a()类似于instanceof操作符,Laravel中还没用到这个方法,这里写个PHPUnit测试,爆绿灯:

    public function testIsA()
    {
        // Arrange
        $child_class = new ChildClass();
        
        // Actual
        $is_object   = is_a($child_class, ChildClass::class);
        $is_subclass = is_a($child_class, ParentClass::class);
        
        // Assert
        $this->assertTrue($is_object);
        $this->assertTrue($is_subclass);
    }

最后,给下整个PHPUnit的测试代码:

<?php

namespace MyRightCapital\Container\Tests;

class IntrospectionTest extends \PHPUnit_Framework_TestCase
{
    public function testClassExists()
    {
        // Arrange
        
        // Actual
        $class_exists = class_exists(TestClassExists::class);
        // Assert
        $this->assertTrue($class_exists);
    }
    
    public function testInterfaceExists()
    {
        // Arrange
        
        // Actual
        $interface_exists = interface_exists(TestInterfaceExists::class);
        // Assert
        $this->assertTrue($interface_exists);
    }
    
    public function testMethodExists()
    {
        // Arrange
        $test_class_exists = new TestClassExists();
        
        // Actual
        $object_method_exists1    = method_exists($test_class_exists, 'testPrivateMethodExists');
        $object_method_exists2    = method_exists($test_class_exists, 'testProtectedMethodExists');
        $object_method_exists3    = method_exists($test_class_exists, 'testPublicMethodExists');
        $classname_method_exists1 = method_exists(TestClassExists::class, 'testPrivateMethodExists');
        $classname_method_exists2 = method_exists(TestClassExists::class, 'testProtectedMethodExists');
        $classname_method_exists3 = method_exists(TestClassExists::class, 'testPublicMethodExists');
        
        // Assert
        $this->assertTrue($object_method_exists1);
        $this->assertTrue($object_method_exists2);
        $this->assertTrue($object_method_exists3);
        $this->assertTrue($classname_method_exists1);
        $this->assertTrue($classname_method_exists2);
        $this->assertTrue($classname_method_exists3);
    }
    
    public function testPropertyExists()
    {
        // Arrange
        $test_class_exists = new TestClassExists();
        
        // Actual
        $private_property1   = property_exists($test_class_exists, 'testPrivatePropertyExists');
        $private_property2   = property_exists(TestClassExists::class, 'testPrivatePropertyExists');
        $protected_property1 = property_exists($test_class_exists, 'testProtectedPropertyExists');
        $protected_property2 = property_exists(TestClassExists::class, 'testProtectedPropertyExists');
        $public_property1    = property_exists($test_class_exists, 'testPublicPropertyExists');
        $public_property2    = property_exists(TestClassExists::class, 'testPublicPropertyExists');
        
        // Assert
        $this->assertTrue($private_property1);
        $this->assertTrue($private_property2);
        $this->assertTrue($protected_property1);
        $this->assertTrue($protected_property2);
        $this->assertTrue($public_property1);
        $this->assertTrue($public_property2);
    }
    
    public function testTraitExists()
    {
        // Arrange
        
        // Actual
        $test_trait_exists = trait_exists(TestTraitExists::class);
        
        // Assert
        $this->assertTrue($test_trait_exists);
    }
    
    public function testClassAlias()
    {
        // Arrange
        class_alias(TestClassExists::class, 'MyRightCapital\Container\Tests\AliasTestClassExists');
        $test_class_exists = new TestClassExists();
        
        // Actual
        $actual = new AliasTestClassExists();
        
        //Assert
        $this->assertInstanceOf(TestClassExists::class, $actual);
        $this->assertInstanceOf(AliasTestClassExists::class, $test_class_exists);
    }
    
    public function testGetClass()
    {
        // Arrange
        $test_class_exists = new TestClassExists();
        
        // Actual
        $class_name = get_class($test_class_exists);
        
        // Assert
        $this->assertSame(TestClassExists::class, $class_name);
    }
    
    public function testGetParentClass()
    {
        // Arrange
        $child_class = new ChildClass();
        
        // Actual
        $parent_class1 = get_parent_class($child_class);
        $parent_class2 = get_parent_class(ChildClass::class);
        
        // Assert
        $this->assertSame(ParentClass::class, $parent_class1);
        $this->assertSame(ParentClass::class, $parent_class2);
    }
    
    public function testGetCalledClass()
    {
        // Arrange
        $child_class  = new ChildClass();
        $parent_class = new ParentClass();
        
        // Actual
        $child_called_class  = $child_class->testGetCalledClass();
        $parent_called_class = $parent_class->testGetCalledClass();
        
        // Assert
        $this->assertSame(ChildClass::class, $child_called_class);
        $this->assertSame(ParentClass::class, $parent_called_class);
    }
    
    public function testInArray()
    {
        $this->assertTrue(in_array('a', ['a', 'b', 1], true));
    }
    
    public function testGetClassMethod()
    {
        // Arrange
        $get_class_methods1 = get_class_methods(ChildClass::class);
        $get_class_methods2 = get_class_methods(new ChildClass());
        
        // Actual
        
        // Assert
        $this->assertFalse(in_array('testPrivateGetClassMethod', $get_class_methods1, true));
        $this->assertFalse(in_array('testPrivateGetClassMethod', $get_class_methods2, true));
        $this->assertFalse(in_array('testProtectedGetClassMethod', $get_class_methods1, true));
        $this->assertFalse(in_array('testProtectedGetClassMethod', $get_class_methods2, true));
        $this->assertTrue(in_array('testPublicGetClassMethod', $get_class_methods1, true));
        $this->assertTrue(in_array('testPublicGetClassMethod', $get_class_methods2, true));
        $this->assertTrue(in_array('testGetCalledClass', $get_class_methods1, true));
        $this->assertTrue(in_array('testGetCalledClass', $get_class_methods2, true));
    }
    
    public function testGetClassVars()
    {
        // Arrange
        
        // Actual
        $class_vars = get_class_vars(ChildClass::class);
        
        // Assert
        $this->assertArrayNotHasKey('privateNoDefaultVar', $class_vars);
        $this->assertArrayNotHasKey('privateDefaultVar', $class_vars);
        $this->assertArrayNotHasKey('protectedNoDefaultVar', $class_vars);
        $this->assertArrayNotHasKey('protectedDefaultVar', $class_vars);
        $this->assertEmpty($class_vars['publicNoDefaultVar']);
        $this->assertEquals('public_laravel', $class_vars['publicDefaultVar']);
    }
    
    public function testGetObjectVars()
    {
        // Arrange
        $get_object_vars = new TestGetObjectVars(1, 2, 3);
        
        // Actual
        $object_vars = get_object_vars($get_object_vars);
        
        // Assert
        $this->assertArrayNotHasKey('x', $object_vars);
        $this->assertArrayNotHasKey('y', $object_vars);
        $this->assertEquals(3, $object_vars['z']);
        $this->assertArrayNotHasKey('dot1', $object_vars);
        $this->assertArrayNotHasKey('dot2', $object_vars);
        $this->assertArrayNotHasKey('circle1', $object_vars);
        $this->assertArrayNotHasKey('circle2', $object_vars);
        $this->assertEquals(10, $object_vars['line1']);
        $this->assertEmpty($object_vars['line2']);
    }
    
    public function testIsSubclassOf()
    {
        // Arrange
        $child_class = new ChildClass();
        
        // Actual
        $is_subclass = is_subclass_of($child_class, ParentClass::class);
        
        // Assert
        $this->assertTrue($is_subclass);
    }
    
    public function testIsA()
    {
        // Arrange
        $child_class = new ChildClass();
        
        // Actual
        $is_object = is_a($child_class, ChildClass::class);
        $is_subclass = is_a($child_class, ParentClass::class);
        
        // Assert
        $this->assertTrue($is_object);
        $this->assertTrue($is_subclass);
    }
}

class TestGetObjectVars
{
    private   $x;
    protected $y;
    public    $z;
    private   $dot1    = 10;
    private   $dot2;
    protected $circle1 = 20;
    protected $circle2;
    public    $line1   = 10;
    public    $line2;
    
    public function __construct($x, $y, $z)
    {
        
        $this->x = $x;
        $this->y = $y;
        $this->z = $z;
    }
}

class ChildClass extends ParentClass
{
    private   $privateNoDefaultVar;
    private   $privateDefaultVar   = 'private_laravel';
    protected $protectedNoDefaultVar;
    protected $protectedDefaultVar = 'protected_laravel';
    public    $publicNoDefaultVar;
    public    $publicDefaultVar    = 'public_laravel';
    
    private function testPrivateGetClassMethod()
    {
    }
    
    protected function testProtectedGetClassMethod()
    {
    }
    
    public function testPublicGetClassMethod()
    {
    }
}

class ParentClass
{
    public function testGetCalledClass()
    {
        return get_called_class();
    }
}

class TestClassExists
{
    private   $testPrivatePropertyExists;
    protected $testProtectedPropertyExists;
    public    $testPublicPropertyExists;
    
    private function testPrivateMethodExists()
    {
    }
    
    protected function testProtectedMethodExists()
    {
    }
    
    public function testPublicMethodExists()
    {
    }
}

interface TestInterfaceExists
{
    
}

trait TestTraitExists
{
    
}

PHP不仅提供了检测class, interface, trait, property, method这些函数Introspection Functions,还提供了一整套的API即反射来检测class, interface, trait, property, method,这些API是好几个类组成的,提供了很多好用的方法。限于篇幅,下篇再聊下反射API。

总结:本文主要聊了下PHP提供的一套检测class, interface, trait, property, method的两个工具包:Introspection Functions和Reflection API,这里先聊到Introspection Functions。下篇再聊下Reflection API的使用,到时见。

© 著作权归作者所有

共有 人打赏支持
botkenni
粉丝 18
博文 406
码字总数 433886
作品 0
西城
程序员
私信 提问
php反射简单使用

1.示例:Yii框架php反射类的使用 //创建$class类的反射类实例对象 $reflection = new ReflectionClass($class); //获取$class类的构造器对象 $constructor = $reflection->getConstructor()......

侯施群
2017/07/18
0
0
From Apprentice To Artisan 翻译 04

上一篇 Reflect Resolution 反射解决方案 One of the most powerful features of the Laravel container is its ability to automatically resolve dependencies via reflection. Reflection......

zgldh
2014/10/08
0
0
如何使用反射来分析PHP的数据结构

更准备的说是 如何用PHP分析类内部的结构。 介绍 当我开始学习PHP编程时,可能并不知道 的强大功能,主要原因是我不需要它来设计我的类,模块甚至是包等等,但是它在很多地方都有非常不错的能...

如来神掌
2018/06/02
0
0
php内核分析(七)-扩展

这里阅读的php版本为PHP-7.1.0 RC3,阅读代码的平台为linux。 我们研究下反射这个扩展。 反射这个扩展目录是存在在:ext/reflection。其实里面的代码很简单。一个.h文件,一个 .c文件。 我们...

王二狗子11
2018/01/07
0
0
php 反射类简介

反射是操纵面向对象范型中元模型的API,其功能十分强大,可帮助我们构建复 杂,可扩展的应用。其用途如:自动加载插件,自动生成文档,甚至可用来扩充 PHP 语言。php 反射api 由若干类组成,...

晨曦之光
2012/03/09
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

推荐一款接口 API 设计神器!

今天栈长给大家推荐一款接口 API 设计神器,传说中的,牛逼哄洪的 Swagger,它到底是什么?今天为大家揭开谜底! Swagger是什么? 官网:https://swagger.io/ Swagger 如官网所示,它是最好的...

Java技术栈
33分钟前
5
0
AMD直奔5nm!这一步棋下得妙

AMD今年将推出采用7nm工艺的第二代EPYC霄龙、第三代Ryzen锐龙处理器,其中后者已经在CES 2019上公开首秀,性能追评i9-9900K,功耗则低得多。 虽然被称为“女友”的GlobalFoundries临时决定放...

linuxCool
39分钟前
3
0
《Migrating to Cloud-Native Application Architectures》学习笔记之Chapter 1. The Rise of Cloud-Native

是什么让互联网公司实现了快速增长? Speed of innovation (快速的创新) Always-available services (服务高可用) Web scale (web高可扩展) Mobile-centric user experiences (以移动...

梦朝思夕
43分钟前
1
0
骄傲的技术人,技术是你的全部吗?

[一] 惊喜 2019年01月30日笔者发布了一篇 <自我剖析,坚持有多难?> 文章,本以为很平常的一篇文章没想到受到了广大技术人员的关注,算是19年的美好开端,继续开拔! 下面进入本篇的正题。 ...

风象南
59分钟前
12
0
Spring boot 入门--1

Spring 简介 spring的诞生历史 微框架,与Spring 4 一起诞生,比如 @RestController。 可以快速上手,整合子项目。 依赖很少的配置就可以快速搭建并且运行项目。...

细节探索者
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部