hyperf框架 model casts 自定义类 php

<?php
namespace App\Transformers;
use Hyperf\Contract\CastsAttributes;
class AmountTransformer implements CastsAttributes
{
    public function get($model, $key, $value, $attributes) :float
    {
        // 在这里对amount字段的值进行自定义转换
        // 例如,保留两位小数
        return (float) $value;
    }

    public function set($model, $key, $value, $attributes)
    {
        return $value;
    }
}

实现CastsAttributes接口

调用

<?php

declare(strict_types=1);

namespace App\Model;

use App\Transformers\AmountTransformer;

class CollectionModel extends Model
{
    protected ?string $table = 'collection';

    protected array $casts = ["amount" => AmountTransformer::class];
}

xiang 发布于  2024-4-9 14:10 

hyperf基于jsonrpc协议微服务用apifox调用 php

{
  "jsonrpc": "2.0",
  "method": "calculator/add",
  "params": [1, 2],
  "id": 1
}

对应服务端的代码

#[RpcService(name: "CalculatorService", protocol: "jsonrpc-http", server: "jsonrpc-http",publishTo: "nacos")]
class CalculatorService implements CalculatorServiceInterface
{
    // 实现一个加法方法,这里简单的认为参数都是 int 类型
    public function add(int $a, int $b): int
    {
        $ss="22";
        // 这里是服务方法的具体实现
        return $a + $b;
    }
}

xiang 发布于  2024-4-9 08:43 

php实现同一类型对象集合(泛型) php

java泛型

import java.util.ArrayList;

class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建一个存储Person对象的ArrayList
        ArrayList<Person> personList = new ArrayList<>();
        personList.add(new Person("Alice"));
        personList.add(new Person("Bob"));

        // 遍历Person对象ArrayList
        for (Person person : personList) {
            System.out.println("Person name: " + person.getName());
        }
    }
}

在上面的示例中,我们创建了一个存储Person对象的ArrayList。通过指定泛型类型为Person,我们可以确保ArrayList只能存储Person对象。然后我们添加两个Person对象到ArrayList中,并通过遍历ArrayList来访问存储的Person对象。

泛型的作用

泛型的作用是在编译时提供更严格的类型检查,并且在编译时捕获和消除类型转换错误。使用泛型可以使代码更加灵活和安全,因为它们允许我们在编译时指定要操作的数据类型。这样可以确保数据的类型安全性,并减少在运行时出现的类型转换错误。泛型还可以提高代码的重用性,因为可以编写可以处理多种类型的通用代码。这使得在编写集合类等数据结构时,可以更好地支持不同类型的数据。

总之,泛型的作用是提供编译时类型安全性、代码重用性和更好的类型检查。

php泛型

而php没有泛型,但我又想实现一个功能是,同一个对象的集合,这个集合只允许添加该对象。

以下是php现实,只接受AdminRulePojo类型的参数

<?php

namespace App\Http\Conllection;

use App\Http\Pojo\AdminRulePojo;

class AdminRuleConllection {
    protected array $conllection=[];

    public function getConllection(): array
    {
        return $this->conllection;
    }

    public function addConllection(AdminRulePojo $adminRulePojo): void
    {
        $this->conllection[] = $adminRulePojo;
    }
}

xiang 发布于  2024-3-26 11:27 

php laravel 依赖注入,自动注入,接口绑定实现类 php

<?php

namespace App\Http\Controllers;

use App\Service\IComputerService;
use App\Validator\IValidator;
use Illuminate\Http\Request;

class IndexController extends Controller
{
    private IComputerService $ComputerService;
    private IValidator $Validator;

    public function __construct(IComputerService $ComputerService, IValidator $Validator)
    {
        $this->ComputerService = $ComputerService;
        $this->Validator = $Validator;
    }

    public function index(Request $request)
    {
        $param = $this->Validator->check($request);

        $res = $this->ComputerService->index($param['per_page']);

        return response()->json($res);
    }
}

以上是一个控制器,

  private IComputerService $ComputerService; 

以上是业务逻辑层,限定IComputerService接口

  <?php

namespace App\Service;

interface IComputerService{
    public function index($per_page);
}

以上是一个IComputerService 业务逻辑层的接口


 public function __construct(IComputerService $ComputerService, IValidator $Validator)
    {
        $this->ComputerService = $ComputerService;
        $this->Validator = $Validator;
    }

以上是把$ComputerService注入到IndexController

那么在哪里自动注入到服务容器呢?

<?php

namespace App\Providers;

use App\Http\Controllers\IndexController;
use App\Service\IComputerService;
use App\Service\impl\ComputerServiceImpl;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     */
    public function register(): void
    {
        //
    //    $this->app->bind(IComputerService::class, ComputerServiceImpl::class);

        $this->app->when(IndexController::class)
            ->needs(IComputerService::class)
            ->give(ComputerServiceImpl::class);
    }

    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        //
    }
}

以上代码是声明IndexController如果需要注入IComputerService接口,会自动调用ComputerServiceImpl实现类.

这样就可以实现代码解偶,符合依赖倒置原则,Dependency inversion principle,抽象不应依赖于细节,细节应依赖于抽象。

控制器如果要替换业务逻辑层即service层,不需要修改控制器的代码,只要新增和替换IComputerService 接口的实现类.

和在服务注册AppServiceProvider里修改一下 对应的实现类就可以了.

这里还有问题要注意.就是IComputerService没有指定返回数据的类型或者对象类型.这样不方便以后的修改或者替换.


xiang 发布于  2024-3-11 15:13 

rabbitmq 定时任务 指定时间发送的队列消息 php

以下是一个使用 RabbitMQ 的延迟队列来实现消息延迟发送的简单示例,使用 PHP 的 AMQP 扩展:

<?php
// 创建连接和channel
$connection = new AMQPStreamConnection('localhost', 5672, 'guest', 'guest');
$channel = $connection->channel();

// 定义延迟队列和目标队列
$delayedQueueName = 'delayed_queue';
$targetQueueName = 'target_queue';

// 声明延迟队列
$channel->queue_declare($delayedQueueName, false, true, false, false, false, [
    'x-dead-letter-exchange' => '',
    'x-dead-letter-routing-key' => $targetQueueName
]);

// 声明目标队列
$channel->queue_declare($targetQueueName, false, true, false, false);

// 创建消息
$messageBody = 'Hello, delayed message!';
$message = new AMQPMessage($messageBody, [
    'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT
]);

// 设置消息的 TTL 为 10 秒
$message->set('expiration', 10000);

// 发送消息到延迟队列
$channel->basic_publish($message, '', $delayedQueueName);

echo " [x] Sent 'Hello, delayed message!'\n";

// 关闭连接
$channel->close();
$connection->close();
?>

在这个示例中,我们创建了一个延迟队列 delayed_queue 和一个目标队列 target_queue。我们发送一条消息到延迟队列,并设置消息的 TTL 为 10 秒。当消息到达延迟时间后,会被投递到目标队列中。

请注意,以上示例仅为演示目的,实际应用中可能需要更多的错误处理和边界情况的考虑。


xiang 发布于  2024-2-29 15:11 

xiang 发布于  2024-2-28 17:42 

php rabbitmq 队列持久化,消息持久化 php

ubuntu停止rabbitmq

service rabbitmq-server stop

ubuntu启动rabbitmq

service rabbitmq-server start

queue队列持久化

  $channel->queue_declare($queue, false, true, false, false);

durable = true 队列持久化


message消息持久化

 $msg = new AMQPMessage('Hello World!'.$time, array('delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT));

重启 rabbitmq-server

queue和ready message依然存在

标签: rabbitmq

xiang 发布于  2024-1-13 10:27 

centos8安装多版本php,remi-php php

安装
https://itlanyan.com/install-newest-php7-and-php8-with-remi-repo/

完全卸载php
https://www.cnblogs.com/NeigeBolg/p/13395128.html

php配置位置
/etc/opt/remi/php73/

软连接 php -v
ln -s /opt/remi/php82/root/usr/bin/php /usr/bin/php

ln -s /opt/remi/php82/root/usr/bin/php-cgi /usr/bin/php-cgi

ln -s /opt/remi/php82/root/usr/bin/phar.phar /usr/bin/php.phar

启动 对应版本php-fpm
service php73-php-fpm restart

标签: php

xiang 发布于  2024-1-2 16:23 

swoole的协程能否减少单个数据库语句查询的时间呢? php

问: 如果一个接口需要查询数据库并返回数据.而这个数据库查询语句需要1秒时间.那么swoole的协程能否减少请求时间呢?

答:
Swoole的协程可以帮助提高并发处理能力,但它并不能直接减少单个数据库查询的执行时间。如果你的数据库查询需要1秒钟,那么无论是否使用协程,这个查询本身的执行时间都是1秒钟。

然而,Swoole的协程可以在等待这个查询结果的同时,去执行其他的任务。例如,如果你有10个这样的查询需要执行,而且这些查询可以并行执行,那么使用Swoole的协程,理论上你可以在大约1秒钟的时间内完成所有的查询,因为这些查询是同时进行的。而如果不使用协程,你可能需要10秒钟的时间,因为每个查询都需要等待上一个查询完成后才能开始。

所以,虽然Swoole的协程不能减少单个查询的执行时间,但它可以通过并行处理来提高整体的处理能力,从而在处理多个查询时,可以显著减少总的等待时间。

标签: swoole

xiang 发布于  2023-12-28 15:34 

swoole框架真的比php-fpm要高并发吗? php

之前写了一篇文章,做了一个粗疏的测试.来证明,在慢数据库查询下,swoole跟php-fpm的并发数一样地少.相差无几.经过网友的讨论和指教.我发现我的结论是错误的且有可能误导其他开发者.

所以现在找一个更加贴近现实的生产环境的测试方法.这里先说结论,swoole是真正能解决php项目性能差,并发低的方案之一.

这里首先要说php-fpm的多进程模式,php-fpm的处理方法.只会一个请求一个请求地处理.怎么证明这个事情?可以写一个sleep(30)秒的接口.开2个静态进程.快速请求两次.然后再去请求其他没有阻塞的接口.看看是不是连其他正常的接口也请求不了.如果是,就能说明php-fpm的处理方法.

但php-fpm的进程是独立.严格上说一个进程慢,需要时间处理,是不会影响其他进程的响应时间的.你可以这样试,同样开两个php-fpm进程,请求一次sleep(30)秒的接口.然后同时压测另外正常的接口.QPS还是有可能上千的.但如果慢的接口的请求把所有的php-fpm进程都占用了,就会影响都其他正常接口的响应速度.出现类似 "阻塞" 的现象.

这个情况也一般php项目速度慢的情况.我认为在介绍,swoole的好处时候.说php-fpm开销大,每次载入框架代码这些其实意义不大.因为一个接口用php-fpm写响应速度是 100ms.换成swoole框架能提高 到80ms.意义不是特别大.

压测方法,

写两个接口,一个等待一秒返回,另一个hello world.同时压测.这样的目的是模拟生产环境.有个别的接口特别慢.拖慢了整个项目的请求速度.
php-fpm sleep代码

sleep(1)

hyperf sleep1秒接口


try {
            $Client= new Client();
            $Client->get("https://www.google.com",["timeout"=>1]);
        }catch (\Exception $exception ){

        }

hello world代码

echo "hello word"

thinkphp8 php-fpm 静态模式 2个进程

单独压测hello world接口

wrk -c 100 -t 10 -d 10s http://tp8.localhost/index/index

QPS 1871

sleep接口和hello world接口,同时压.

wrk -c 10 -t 10 -d 10s http://tp8.localhost/sleep/index/

wrk -c 100 -t 10 -d 10s http://tp8.localhost/index/index

hello world接口 QPS 19.97

hyperf 开2个进程

hyperf 不用sleep模拟慢接口,用http请求来模拟.

hello world接口单独压测

wrk -c 100 -t 10 -d 10s http://127.0.0.1:9501/index

QPS 58576

sleep接口和hello world接口,同时压.
wrk -c 10 -t 10 -d 10s http://127.0.0.1:9501/sleep
wrk -c 100 -t 10 -d 10s http://127.0.0.1:9501/index

hello world接口 QPS 56826

hello world接口几乎没有受慢接口影响

得出结论

单个接口请求,php-fpm跟swoole也许有10倍的差距.但是这个不是重点.重点是采用swoole框架写的项目整体不会被慢的接口拖慢.这个比较有意义.

这里说的swoole性能比php-fpm强10倍.不是说一个接口用来用php-fpm请求时间是1秒,改用了swoole框架就变成了0.1秒.
而是说某些情况.swoole的并发数可以比php-fpm高10倍.

为什么php-fpm会出现"阻塞"的情况.和什么情况下才会出现阻塞.
php-fpm进程数是20,一个sleep(1)的接口,每秒并发请求数为20.这样就会把20个进程用占用.而其他接口的请求就会出现"阻塞"的情况.因为没有进程可用了,但如果并发是10去请求慢接口.还有剩下10个进程去处理其他接口的请求.这时候就不会出现"阻塞".

google请求解释

   $Client->get("https://www.google.com",["timeout"=>1]);

解释一下请求google地址,在墙内一定是请求不到的.设置1秒超时.为了代替php-fpm的sleep1秒.

标签: php

xiang 发布于  2023-12-27 16:28