把340万个单词的csv文件写进redis队列

<?php

declare(strict_types=1);

namespace App\Command;

use Hyperf\Command\Command as HyperfCommand;
use Hyperf\Command\Annotation\Command;
use Hyperf\Context\ApplicationContext;
use League\Csv\Reader;
use Psr\Container\ContainerInterface;

#[Command]
class FooCommand extends HyperfCommand
{
    public function __construct(protected ContainerInterface $container)
    {
        parent::__construct('demo:command');
    }

    public function configure()
    {
        parent::configure();
        $this->setDescription('Hyperf Demo Command');
    }

    public function handle()
    {
        $stime = microtime(true);
        $reader = Reader::createFromPath('/var/www/html/hyperf/hyperf-csv/stardict.csv', 'r');
        $reader->setHeaderOffset(0);
        $records = $reader->getRecords();

        foreach ($records as $record) {
            if (count($record) == 1 && $record[0] === '') {
                return;
            }
            $word = preg_replace('/[^\w\s]/u', '', $record['word']);
            $_insert['word'] = $word;
            $_insert['phonetic'] = $record['phonetic'];
            $_insert['definition'] = $record['definition'];
            $_insert['translation'] = $record['translation'];
            $key = "dict";
            $value = json_encode($_insert);

            $container = ApplicationContext::getContainer();
            $redis = $container->get(\Hyperf\Redis\Redis::class);
            $redis->lPush($key, $value);

            print_r($word."\n");
        }

        $etime = microtime(true);
        $total = $etime - $stime;

        print_r($total);
    }
}

耗时176秒,内存400多MB。


xiang 发布于  2024-7-12 10:58 

My Resume,PHP backend programmer

Expert knowledge in PHP 7 and 8

Expert knowledge in Laravel ,Thinkphp,Yii2,Hyperf,Swoole

Expert knowledge in API design and development,Websocket,Http,TCP

Expert knowledge in Rabbitmq,Linux,Redis

Expert knowledge in Test Driven Development where tests are used to drive feature completeness and correctness. A strong understanding of Laravel testing best practices using Facades, Database assertions and JSON validation.

Solid knowledge of SQL relational databases, schema design and query optimization

Solid knowledge of web application security best practices (XSS, SQL Injection, etc)

Solid knowledge of utilizing queues and caching

Experience working with Agile SCRUM based teams

The types of applications I have developed include online video education applications, IoT (Internet of Things) servers, online shopping malls, English learning applications, and ERP (Enterprise Resource Planning) systems.

Good English reading and listening skills

If you are looking for an experienced and affordable PHP backend programmer, please email me at 1124557724#qq.com


xiang 发布于  2024-7-5 08:54 

看英语字幕视频学英语app开发日记 php

产品介绍

这是一款通过看视频看英语字幕来学习英语的app,根据的外语学习理论是可理解性输入。进行大量的可以理解性的英语内容输入,可以实现有效的外语学习,不需要枯燥的背单词,学语法。

网址:https://eng.devxiang.com/videoDetail/10
(仅支持手机端浏览器访问。)

笔者是一个后端程序员和这个产品的发起人,和我一起合作的还有一名vuejs前端开发者。



6月26日

  1. 完成了单词词库的构建,有49000多个英语单词。使用了github上的开源词库。导进mysql数据表。写成接口,现在打算开放给大家免费使用,如果有需要的话,欢迎使用。

单词查询接口文档
https://apifox.com/apidoc/shared-9931ba6d-69fc-471c-a874-aff60ee3bbcb

  1. 完成了视频详情接口,前端完全了字幕独立加载,按时间展示,支持分词点击查询单词中文意思。但目前只支持手机浏览器访问,pc端浏览器还没有做兼容。

按敏捷开发原则,快速开发出产品原型,最小可使用的版本。第一版已经支持视频播放,字幕独立展示,可以点击查询。算是可以使用的了。

3.未来功能安排,
3.1 通过ai接口 视频的音频识别生成英语字幕。
3.2 用户单词表功能,生词可以加入单词表学习。
3.3 背单词功能。


xiang 发布于  2024-6-26 13:57 

下载youtube字幕

[该文章已加密,请点击标题输入密码访问]


xiang 发布于  2024-6-25 17:55 

linux微信

http://archive.ubuntukylin.com/ubuntukylin/pool/partner/weixin_2.1.1_amd64.deb

亲测可用。

腾讯这公司,就是不肯出linux版微信。


xiang 发布于  2024-5-24 09:24 

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 

面向对象设计原则 Dependency Inversion Principle 依赖倒置原则 简单版

Dependency Inversion Principle 依赖倒置原则 dip

dip有两个原则
1.高层模块不应该依赖于底层模块,二者都应该依赖抽象
2.抽象不应该依赖细节,细节应该依赖于抽象

举一个例子

后端项目,写一个数据列表的接口。

返回数据的格式如下:

{
  "code": 0,
  "message": "成功",
  "data": {
    "conllection": [
      {
        "id": 76,
        "pid": 0,
        "type": "menu",
        "title": "",
        "name": "",
        "path": "",
        "icon": "local-logo",
        "menu_type": null,
        "url": "",
        "component": "",
        "keepalive": 0,
        "extend": "none",
        "remark": "",
        "weigh": 0,
        "status": "1",
        "update_time": null,
        "create_time": null
      }
    ],
    "current_page": 1,
    "per_page": 1,
    "total": 1
  }
}

把返回的数据字段和类型都定义好的话,这个接口就可以跟前端对接。所以先把接口字段定义好。是一个有效率的做法。

现在项目分三层,控制层->服务层(获取数据)->数据仓库层->模型层等等。从高到低。如果遵循依赖倒置原则,我现在只要定义好数据响应类就是以上的json生成的class.

和写好一个接口来定义控制层和服务层使用什么参数和返回值来作数据交换就可以。

定义admin_role类

public class AdminRole {
    private int id;
    private int pid;
    private String type;
    private String title;
    private String name;
    private String path;
    private String icon;
    private String menuType;
    private String url;
    private String component;
    private int keepalive;
    private String extend;
    private String remark;
    private int weigh;
    private String status;
    private String update_time;
    private String create_time;

    // 省略getter和setter方法
}

xiang 发布于  2024-3-26 15:53 

面向对象设计原则 Dependency Inversion Principle 依赖倒置原则 php实现 面向对象

Dependency Inversion Principle 依赖倒置原则 dip

dip有两个原则
1.高层模块不应该依赖于底层模块,二者都应该依赖抽象
2.抽象不应该依赖细节,细节应该依赖于抽象

举一个例子

php后端项目,写一个列表数据的接口,带分页功能

输入的参数 有两个 page和per_page,

输出接口的字段有
total 数据的总数
per_page 每页数
current_page 当前页数
collection 具体的数据集合

以下是mysql的表结构

CREATE TABLE ba_admin_rule (
id int unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
pid int unsigned NOT NULL DEFAULT '0' COMMENT '上级菜单',
type enum('menu_dir','menu','button') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'menu' COMMENT '类型:menu_dir=菜单目录,menu=菜单项,button=页面按钮',
title varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '标题',
name varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '规则名称',
path varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '路由路径',
icon varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '图标',
menu_type enum('tab','link','iframe') COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '菜单类型:tab=选项卡,link=链接,iframe=Iframe',
url varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT 'Url',
component varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '组件路径',
keepalive tinyint unsigned NOT NULL DEFAULT '0' COMMENT '缓存:0=关闭,1=开启',
extend enum('none','add_rules_only','add_menu_only') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'none' COMMENT '扩展属性:none=无,add_rules_only=只添加为路由,add_menu_only=只添加为菜单',
remark varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '备注',
weigh int NOT NULL DEFAULT '0' COMMENT '权重',
status enum('0','1') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '1' COMMENT '状态:0=禁用,1=启用',
update_time bigint unsigned DEFAULT NULL COMMENT '更新时间',
create_time bigint unsigned DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (id),
KEY pid (pid)
) ENGINE=InnoDB AUTO_INCREMENT=91 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC COMMENT='菜单和权限规则表';

生成的pojo类

<?php

namespace App\Http\Pojo;

class AdminRulePojo
{
    private int $id;
    private int $pid = 0;
    private string $type = 'menu';
    private string $title = '';
    private string $name = '';
    private string $path = '';
    private string $icon = '';
    private ?string $menu_type = null;
    private string $url = '';
    private string $component = '';
    private int $keepalive = 0;
    private string $extend = 'none';
    private string $remark = '';

    private int $weigh = 0;
    private string $status = '1';
    private ?int $update_time = null;
    private ?int $create_time = null;

    public function getId(): int
    {
        return $this->id;
    }

    public function setId(int $id): void
    {
        $this->id = $id;
    }

    public function getPid(): int
    {
        return $this->pid;
    }

    public function setPid(int $pid): void
    {
        $this->pid = $pid;
    }

    public function getType(): string
    {
        return $this->type;
    }

    public function setType(string $type): void
    {
        $this->type = $type;
    }

    public function getTitle(): string
    {
        return $this->title;
    }

    public function setTitle(string $title): void
    {
        $this->title = $title;
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function setName(string $name): void
    {
        $this->name = $name;
    }

    public function getPath(): string
    {
        return $this->path;
    }

    public function setPath(string $path): void
    {
        $this->path = $path;
    }

    public function getIcon(): string
    {
        return $this->icon;
    }

    public function setIcon(string $icon): void
    {
        $this->icon = $icon;
    }

    public function getMenuType(): ?string
    {
        return $this->menu_type;
    }

    public function setMenuType(?string $menu_type): void
    {
        $this->menu_type = $menu_type;
    }

    public function getUrl(): string
    {
        return $this->url;
    }

    public function setUrl(string $url): void
    {
        $this->url = $url;
    }

    public function getComponent(): string
    {
        return $this->component;
    }

    public function setComponent(string $component): void
    {
        $this->component = $component;
    }

    public function getKeepalive(): int
    {
        return $this->keepalive;
    }

    public function setKeepalive(int $keepalive): void
    {
        $this->keepalive = $keepalive;
    }

    public function getExtend(): string
    {
        return $this->extend;
    }

    public function setExtend(string $extend): void
    {
        $this->extend = $extend;
    }

    public function getRemark(): string
    {
        return $this->remark;
    }

    public function setRemark(string $remark): void
    {
        $this->remark = $remark;
    }

    public function getWeigh(): int
    {
        return $this->weigh;
    }

    public function setWeigh(int $weigh): void
    {
        $this->weigh = $weigh;
    }

    public function getStatus(): string
    {
        return $this->status;
    }

    public function setStatus(string $status): void
    {
        $this->status = $status;
    }

    public function getUpdateTime(): ?int
    {
        return $this->update_time;
    }

    public function setUpdateTime(?int $update_time): void
    {
        $this->update_time = $update_time;
    }

    public function getCreateTime(): ?int
    {
        return $this->create_time;
    }

    public function setCreateTime(?int $create_time): void
    {
        $this->create_time = $create_time;
    }
}

先声明接口的字段,这样可以快速跟前端对接。

{
  "code": 0,
  "message": "成功",
  "data": {
    "conllection": [
      {
        "id": 76,
        "pid": 0,
        "type": "menu",
        "title": "",
        "name": "",
        "path": "",
        "icon": "local-logo",
        "menu_type": null,
        "url": "",
        "component": "",
        "keepalive": 0,
        "extend": "none",
        "remark": "",
        "weigh": 0,
        "status": "1",
        "update_time": null,
        "create_time": null
      }
    ],
    "current_page": 1,
    "per_page": 1,
    "total": 1
  }
}

这个是定义好的分页数据返回类,

<?php

namespace App\Http\Pagination;

use App\Http\Pojo\AdminRulePojo;

class AdminRulePagination
{
    // use Pagination;

    protected int $current_page;

    protected int $per_page;

    protected int $total;
    protected array $conllection = [];

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

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

    public function getCurrentPage(): int
    {
        return $this->current_page;
    }

    public function setCurrentPage(int $current_page): void
    {
        $this->current_page = $current_page;
    }

    public function getPerPage(): int
    {
        return $this->per_page;
    }

    public function setPerPage(int $per_page): void
    {
        $this->per_page = $per_page;
    }

    public function getTotal(): int
    {
        return $this->total;
    }

    public function setTotal(int $total): void
    {
        $this->total = $total;
    }
}

因为php不支持泛型。所以用以下的方法来实现同一对象集合

 protected array $conllection = [];

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

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

然后定义list返回数据的接口,定义好接收的参数和返回的类型.

<?php

namespace App\Http\Service;

use App\Http\Pagination\AdminRulePagination;

interface IAdminRuleService
{
    public function list(int $per_page) :AdminRulePagination;
}

接口实现类

<?php

namespace App\Http\Service\impl;

use App\Http\Pagination\AdminRulePagination;
use App\Http\Pojo\AdminRulePojo;
use App\Http\Service\IAdminRuleService;
use App\Models\AdminRuleModel;

class AdminRuleService implements IAdminRuleService
{
    private AdminRuleModel $adminRuleModel;

    private AdminRulePagination $adminRulePagination;

    public function __construct(AdminRuleModel $adminRuleModel,AdminRulePagination $adminRulePagination)
    {
        $this->adminRuleModel=$adminRuleModel;
        $this->adminRulePagination=$adminRulePagination;
    }

    public function list(int $per_page) :AdminRulePagination
    {
        $res = $this->adminRuleModel::where('status', 1)->paginate($per_page)->toArray();

        if (!empty($res['data'])) {
            foreach ($res['data'] as $item) {
                $AdminRulePojo = new AdminRulePojo();
                $AdminRulePojo->setComponent($item['component']);
                $AdminRulePojo->setId($item['id']);
                $AdminRulePojo->setIcon($item['icon']);
                $this->adminRulePagination->addConllection($AdminRulePojo);
            }
        }

        $this->adminRulePagination->setCurrentPage($res['current_page']);
        $this->adminRulePagination->setTotal($res['total']);
        $this->adminRulePagination->setPerPage($res['per_page']);

        return $this->adminRulePagination;
    }
}

使用laravel的服务容器,控制反转,来绑定接口和实现类。

$this->app->bind(IAdminRuleService::class, AdminRuleService::class);

定义好接口

之后的实现类。可以换成原生sql查询的。其他数据库查询的。

比如mangodb获取数据的。

<?php

namespace App\Http\Service\impl;

use App\Http\Pagination\AdminRulePagination;
use App\Http\Pojo\AdminRulePojo;
use App\Http\Service\IAdminRuleService;
use App\Models\AdminRuleModel;
use Illuminate\Support\Facades\DB;

class MangoDbAdminRuleService implements IAdminRuleService
{
    private AdminRulePagination $adminRulePagination;

    public function __construct(AdminRulePagination $adminRulePagination)
    {
        $this->adminRulePagination=$adminRulePagination;
    }

    public function list(int $per_page) :AdminRulePagination
    {

    }
}

在服务容器那里改一下绑定就可以了。

 $this->app->bind(IAdminRuleService::class, MangoDbAdminRuleService::class);

这个是控制器,声明接口变量IAdminRuleService

<?php

namespace App\Http\ServiceController;

use App\Http\Service\IAdminRuleService;

class AdminRule
{
    use ServiceController;

    use Response;

    private IAdminRuleService $adminRuleService;

    public function __construct(IAdminRuleService $adminRuleService)
    {
        $this->adminRuleService = $adminRuleService;
    }

    public function list(int $per_page): array
    {
        $obj = $this->adminRuleService->list($per_page);

        $data = $this->objectToArray($obj);

        $this->setData($data);

        return $this->Success();
    }
}

以上就是这个依赖倒置的例子。

这个php的api接口查询数据的例子。可以随时换框架,随时换数据库操作类。使用orm或者sql查询的都行,也可以换数据库类型。

控制器作为高层模块,不依赖低层service层模块。两者通过接口和定义好的数据类AdminRulePagination来交换数据。

符合了依赖倒置的两大原则

1.高层模块不应该依赖于底层模块,二者都应该依赖抽象

2.抽象不应该依赖细节,细节应该依赖于抽象

抽象不依赖细节,按这个例子的情况就是,控制器层依赖IAdminRuleService接口,而不是依赖具体的实现类。

这个例子有点复杂。说了一些泛型的东西。但是实现这个过程中,会遇到php的缺点和不足。如果以上的例子用java实现。那就会容易一些。


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

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