标签: php8

  • Symfony6生产环境Twig导致构建失败小记录

    最近把Symfony4升级到6,php版本也跟着升到8.2.5,体验了把新版本好处,但发现几个问题。

    默认的构建命令,symfony new my_project_directory --version="6.2.*",这是一个典型的API项目,也是我创建的类型。在API环境下,生产环境显然是不用任何模板功能的,但因为开发环境需要模板做展示,所以上线时候产生了一个BUG。

    当你加入composer.phar require --dev profiler为dev环境添加调试条的时候,你会发现一个问题,所有基于Profiler的依赖,例如Twig确实在composer.json的dev里。但是,在config/Bundles.php里却把因为Profiler依赖而加入的Twig模板引擎标记为全环境都需要Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true],这里要改成Symfony\Bundle\TwigBundle\TwigBundle::class => ['dev' => true, 'test' => true]

    但这时候还没有完,config/packages/twig.yaml也需要删除,否则Symfony启动的时候检查到配置文件会自动调用,而导致报错。顺便把templates目录删除,这个是Twig默认加入的模板文件。

    最后,记得一点,composer install --no-dev --no-ansi --no-interaction --no-progress --classmap-authoritative --no-scripts --prefer-dist在你的composer安装命令中,千万不要--no-plugins,这会导致/vendor/autoload_runtime.php无法生成!

  • 做了一个PHP8的Docker镜像

    花了大概30分钟时间,做了一个PHP8的自用镜像,为什么那么快呢?因为是基于以前的PHP7修改而来的呀,这下就有JIT的支持了!

    docker hub官方地址:https://hub.docker.com/r/nickzhuo/phpallinone
    源代码地址:https://github.com/nickzhuo/phpallinone

  • 利用Attribute特性和ValueResolverInterface为Symfony注入IP

    PHP8发布之后越发爱不释手,尤其Attribute比Annotation强大不少,Attribute可以对单个参数进行控制,这个功能很强大。演示一下控制器中通过Attribute描述字段来获得当前IP,其实一般解析器都是用来denormalize客户端POST过来的参数,但是为了用到Attribute,我用IP来举例。

    <?php
    namespace App\Resolver;
    use Attribute;
    
    #[Attribute(Attribute::TARGET_PARAMETER)]
    final class IP
    {
    }

    先设计一个Attribute申明,注意TARGET_PARAMETER标识作用在参数范围。

    <?php
    namespace App\Resolver;
    use Symfony\Component\HttpFoundation\Request;
    use Symfony\Component\HttpKernel\Controller\ValueResolverInterface;
    use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
    
    class IPValueResolver implements ValueResolverInterface
    {
        public function resolve(Request $request, ArgumentMetadata $argument): iterable
        {
            $argumentType = $argument->getType();
            // 检查IP的Attribute
            $attributes = $argument->getAttributes(IP::class);
            if (count($attributes) == 0 || $argumentType !== 'string') {
                return [];
            }
            yield $request->getClientIp();
        }
    }

    其次,编写一个解析器,注意,Symfony 6.2开始提供ValueResolverInterface,之前版本用ArgumentValueResolverInterface

    public function resolver(#[IP] string $ip): Response

    最后,便是在任何控制器的方法中,只要使用了#[IP] string $ip就能方便的取得IP了。正确使用解析器,可以大大降低控制器中和Request对象耦合的重复代码,将预处理的流程都放在解析中!

  • 从PHP 7.4升级到PHP 8.2是惊人的变化

    一直工作在PHP7的版本下,最近把环境都挪到了PHP8下面,具体用的是最新的8.2.3版本。不得不说,这个变化是天翻地覆的,有很多专门的文章写了PHP8的特点,我也稍微记录下自己角度的观察。

    • 支持更多强类型,这个在php7里其实也可以有,叫做标量,打开严格模式即可,但问题是提供的类型不多。PHP8就基本支持了完整的类型,包括方法的返回值,这样的写法对内存的使用处置肯定有极大好处的。
      public function weibo(WeiboService $weiboService):Response
    • 支持使用问号?的null的返回,虽然php是脚本语言,但这个东东其实在现在语言里很有用,可见未来会有更完整的nullable支持,但历史代码库肯定要做大规模升级,同时也需要java里optional类的支持。
    public function share(string $text, string $ip, ?string $pic = null): void
    • 有了枚举,让代码阅读起来更清晰更清晰,同时作为形参可以限制范围,而不是要判断int取值的范围。
    enum PlatformConfig: int
    {
        case TENCENT = 1;
        case BAIDU = 2;
        case ALIPAY = 3;
        case APP_ANDROID = 4;
        case APP_IOS = 5;
    }
    • readonly关键字,提升代码效率,8.2支持class级别的readonly。也就是说在写构造函数的时候,可以用readonly确认类对象的只读属性,用private来控制访问级别,简化类对象的初始化,唯一有个小缺点,既然都干净了,为什么不把body的{}花括号一起省略掉呢,代码可以更美观。
    readonly class LoginSubscriber implements EventSubscriberInterface
    {
        public function __construct(private TokenStorageInterface $storage, private JWTService $manager, private LoginRepository $loginRepository)
        {
        }
    }
    • readonly进阶带来一个特性,简单来说就是immutable风格对象,例如在跨平台前段Flutter框架里,所有的对象都是不可变的。这种风格的写法带来一个好处就是可以方便计算对象是否变化,但如果要改变某个属性,要做的是为类提供一个类似copyWith的方法,改变内部值并且返回一个新的对象,新对象肯定有有新的hashcode。Flutter因为是基于Dart的,Dart没有反射,但PHP又反射,所以可以用第三方的包来实现这种设计风格。
    class Post
    {
        use Cloneable;
        public readonly string $title;
        public readonly string $author;
        public function __construct(string $title, string $author)
        {
            $this->title = $title;
            $this->author = $author;
        }
    }
    

    总结就是,PHP8是划时代的,更具有方向性的,我们可以知道PHP团队走在一条正确的道路上。:D