Tp5使用命令行模式,自定义指令

本文介绍如何在 ThinkPHP 5.1 中创建自定义命令,包括创建命令类、配置命令及在控制器中调用命令的方法。同时介绍了快速生成指令的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一步,创建一个自定义命令类文件,新建application/common/command/Hello.php

<?php
namespace app\common\command;

use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;

class Hello extends Command
{
    protected function configure()
    {
        $this->setName('hello')
        	->addArgument('name', Argument::OPTIONAL, "your name")
            ->addOption('city', null, Option::VALUE_REQUIRED, 'city name')
        	->setDescription('Say Hello');
    }

    protected function execute(Input $input, Output $output)
    {
    	$name = trim($input->getArgument('name'));
      	$name = $name ?: 'thinkphp';

		if ($input->hasOption('city')) {
        	$city = PHP_EOL . 'From ' . $input->getOption('city');
        } else {
        	$city = '';
        }
        
        $output->writeln("Hello," . $name . '!' . $city);
    }
}

这个文件定义了一个叫hello的命令,并设置了一个name参数和一个city选项。

第二步,配置application/command.php文件

<?php
return [
    'app\common\command\Hello',
];

V5.1.24+版本开始,你可以定义为下面的方式提高性能。

<?php
return [
	// 指令名 =》完整的类名
    'hello'	=>	'app\common\command\Hello',
];

第三步,测试-命令帮助-命令行下运行

php think

输出

Think Console version 0.1

Usage:
  command [options] [arguments]

Options:
  -h, --help            Display this help message
  -V, --version         Display this console version
  -q, --quiet           Do not output any message
      --ansi            Force ANSI output
      --no-ansi         Disable ANSI output
  -n, --no-interaction  Do not ask any interactive question
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug

Available commands:
  build              Build Application Dirs
  clear              Clear runtime file
  hello              Say Hello 
  help               Displays help for a command
  list               Lists commands
 make
  make:controller    Create a new resource controller class
  make:model         Create a new model class
 optimize
  optimize:autoload  Optimizes PSR0 and PSR4 packages to be loaded with classmaps too, good for production.
  optimize:config    Build config and common file cache.
  optimize:schema    Build database schema cache.

第四步,运行hello命令

php think hello

输出

Hello thinkphp!

添加命令参数

php think hello liuchen

输出

Hello liuchen!

添加city选项

php think hello liuchen --city shanghai

输出

Hello thinkphp!
From shanghai

注意看参数和选项的调用区别

在控制器中调用命令

支持在控制器的操作方法中直接调用命令,例如:

<?php
namespace app\index\controller;

use think\Console;
use think\Controller;

class Index extends Controller
{
    public function hello($name)
    {
        $output = Console::call('hello ' . $name);

        return $output->fetch();
    }
}

访问该操作方法后,例如:

http://tp5.com/index/index/hello/name/thinkphp

页面会输出

Hello thinkphp!

一旦在控制器中调用命令,并不会生成cli命令行日志,而是在普通的web日志中记录。

快速生成指令(V5.1.24+

V5.1.24+版本开始,你可以通过命令行指令快速生成一条指令,包括指令类文件,例如:

php think make:command First first

First表示类名,实际生成的指令类则是app\command\First(自动生成的指令类的命名空间默认都是 app\command)。

first表示指令名,建议统一使用小写,如果不传入该参数,则默认用类名的小写作为指令名。

为了让指令可以无需定义自动调用,需要在你的应用配置的console.php配置文件中,增加下面的配置参数:

'auto_path' => env('app_path') . 'command/',

配置后, 你可以在命令行测试下刚才新生成的指令。

php think first

输出结果为:

first

你可以编辑app\command\First类,完成实际的指令任务。

注意,如果你生成了指定命名空间的指令,但又不是你配置的自动加载目录,那么仍然需要在command.php 文件中定义指令。

如果需要生成一个指定的命名空间,可以使用:

php think make:command app\index\Second second

转自:看云https://www.kancloud.cn/manual/thinkphp5_1/354146

 

 

<think>我们正在使用ThinkPHP8和Vue3来实现WebSocket连接。根据引用内容,我们可以知道在ThinkPHP中可以使用Workerman或GatewayWorker(基于Workerman)来搭建WebSocket服务。在Vue3中,我们可以使用原生的WebSocket或者兼容性更好的socket.io-client(如果需要更好的兼容性,尤其是在小程序或App中)。但根据用户要求,我们使用原生WebSocket。 步骤: 1. 后端(ThinkPHP8)搭建WebSocket服务器。 2. 前端(Vue3)建立WebSocket连接,并处理消息。 参考引用[1][2][4][5],我们可以采用以下方法: 后端(ThinkPHP8): 由于ThinkPHP8默认不包含Workerman,我们需要通过Composer安装Workerman。 安装Workerman: ```bash composer require workerman/workerman ``` 然后,我们可以创建一个自定义命令来启动WebSocket服务器。在ThinkPHP8中,我们可以创建一个命令行工具类。 例如,在`app/command`目录下创建`WebSocket.php`: ```php <?php namespace app\command; use think\console\Command; use think\console\Input; use think\console\Output; use Workerman\Worker; class WebSocket extends Command { protected function configure() { $this->setName('websocket:start')->setDescription('Start WebSocket server'); } protected function execute(Input $input, Output $output) { // 创建一个Worker监听2345端口,使用websocket协议通讯 $ws_worker = new Worker('websocket://0.0.0.0:2345'); // 启动4个进程对外提供服务 $ws_worker->count = 4; // 当收到客户端发来的数据后返回给客户端 $ws_worker->onMessage = function($connection, $data) { // 向客户端发送数据 $connection->send('Server received: ' . $data); }; // 运行worker Worker::runAll(); } } ``` 然后,我们需要在`config/console.php`中注册这个命令: ```php return [ 'commands' => [ 'websocket:start' => 'app\command\WebSocket', ], ]; ``` 启动服务: ```bash php think websocket:start ``` 这样,WebSocket服务器就在2345端口上运行了。 前端(Vue3): 在Vue3中,我们可以使用原生WebSocket API。为了更好的管理,我们可以将WebSocket封装成一个可复用的模块(例如使用Composition API或Pinia)。 这里我们参考引用[1]和[4],使用Pinia来管理WebSocket连接。 首先,安装Pinia(如果尚未安装): ```bash npm install pinia ``` 然后,在`src/stores`目录下创建一个`websocket.js`: ```javascript import { defineStore } from 'pinia'; export const useWebSocketStore = defineStore('websocket', { state: () => ({ websocket: null, messages: [], online: false, }), actions: { // 建立连接 connect() { // 如果已经连接或者正在连接,则不再创建 if (this.websocket && this.websocket.readyState === WebSocket.OPEN) { return; } // 创建WebSocket连接,这里假设后端运行在本地2345端口 this.websocket = new WebSocket('ws://localhost:2345'); // 连接成功 this.websocket.onopen = () => { this.online = true; console.log('WebSocket connected'); }; // 接收消息 this.websocket.onmessage = (event) => { this.messages.push(event.data); }; // 连接关闭 this.websocket.onclose = () => { this.online = false; console.log('WebSocket disconnected'); }; // 错误处理 this.websocket.onerror = (error) => { console.error('WebSocket error:', error); }; }, // 发送消息 send(message) { if (this.websocket && this.websocket.readyState === WebSocket.OPEN) { this.websocket.send(message); } else { console.error('WebSocket is not connected'); } }, // 关闭连接 disconnect() { if (this.websocket) { this.websocket.close(); this.websocket = null; this.online = false; } }, }, }); ``` 在Vue组件中使用: ```vue <template> <div> <button @click="connect">连接</button> <button @click="disconnect">断开</button> <input v-model="message" type="text" /> <button @click="send">发送</button> <ul> <li v-for="(msg, index) in messages" :key="index">{{ msg }}</li> </ul> </div> </template> <script setup> import { ref } from 'vue'; import { useWebSocketStore } from '@/stores/websocket'; const store = useWebSocketStore(); const message = ref(''); const connect = () => { store.connect(); }; const disconnect = () => { store.disconnect(); }; const send = () => { if (message.value.trim() !== '') { store.send(message.value); message.value = ''; } }; </script> ``` 注意:以上是一个简单示例。实际应用中,你可能需要处理更复杂的消息格式(如JSON),以及重连机制等。 另外,如果考虑跨域问题,需要在WebSocket服务器端设置允许跨域(如设置HTTP头),但Workerman本身不涉及浏览器跨域,因为WebSocket协议本身支持跨域,但浏览器会检查服务器是否在同一个域或是否允许跨域。如果前端和后端WebSocket服务器不在同一个域,需要确保WebSocket服务器支持跨域(通常通过设置`Origin`头验证,或者使用Nginx代理)。 以上代码实现了基本的WebSocket通信。根据引用[5],如果你需要更复杂的功能(如用户认证、群聊等),你可能需要使用GatewayWorker,它提供了更丰富的功能。 引用[2]提到了使用phpsocket.io,但这里我们使用原生WebSocket,因为Vue3中可以直接使用WebSocket API。 总结: 1. 后端通过Workerman创建WebSocket服务器。 2. 前端Vue3使用Pinia管理WebSocket连接,包括连接、发送消息、接收消息和断开连接。 注意:在生产环境中,你可能需要配置SSL(wss://)以确保安全。 相关问题: 1. 如何在ThinkPHP8中使用Workerman实现WebSocket服务器? 2. Vue3中如何封装WebSocket连接? 3. WebSocket通信中如何实现用户认证? 4. 如何实现WebSocket的重连机制? 5. 如何保证WebSocket通信的安全性(使用wss)?</think>### ThinkPHP8 与 Vue3 实现 WebSocket 连接指南 #### 一、后端实现(ThinkPHP8 + Workerman) 1. **安装依赖** ```bash composer require workerman/workerman ``` 2. **创建 WebSocket 服务** (`app/socket/WebSocket.php`) ```php <?php namespace app\socket; use Workerman\Worker; use think\facade\Db; class WebSocket { public function start() { $worker = new Worker('websocket://0.0.0.0:2346'); $worker->count = 4; $worker->onConnect = function ($connection) { echo "New connection\n"; }; $worker->onMessage = function ($connection, $data) { // 处理消息逻辑 (示例:广播消息) foreach ($worker->connections as $client) { $client->send(json_encode([ 'type' => 'message', 'data' => $data ])); } }; $worker->onClose = function ($connection) { echo "Connection closed\n"; }; Worker::runAll(); } } ``` 3. **创建启动命令** (`app/command/Socket.php`) ```php <?php namespace app\command; use think\console\Command; use think\console\Input; use think\console\Output; use app\socket\WebSocket; class Socket extends Command { protected function configure() { $this->setName('socket:start')->setDescription('Start WebSocket server'); } protected function execute(Input $input, Output $output) { (new WebSocket())->start(); } } ``` 4. **启动服务** ```bash php think socket:start ``` #### 二、前端实现(Vue3 + WebSocket) 1. **创建 WebSocket 工具** (`src/utils/socket.js`) ```javascript import { ref } from 'vue' export function useWebSocket(url) { const socket = ref(null) const messages = ref([]) const isConnected = ref(false) const connect = () => { socket.value = new WebSocket(url) socket.value.onopen = () => { isConnected.value = true console.log('WebSocket connected') } socket.value.onmessage = (event) => { messages.value.push(JSON.parse(event.data)) } socket.value.onerror = (error) => { console.error('WebSocket error:', error) } socket.value.onclose = () => { isConnected.value = false console.log('WebSocket disconnected') } } const send = (data) => { if (isConnected.value) { socket.value.send(JSON.stringify(data)) } } const disconnect = () => { if (socket.value) { socket.value.close() } } return { messages, isConnected, connect, send, disconnect } } ``` 2. **在组件中使用** (`src/components/Chat.vue`) ```vue <template> <div> <button @click="connect">连接</button> <button @click="disconnect">断开</button> <input v-model="message" placeholder="输入消息"> <button @click="sendMessage">发送</button> <ul> <li v-for="(msg, index) in messages" :key="index"> {{ msg.data }} </li> </ul> </div> </template> <script setup> import { ref } from 'vue' import { useWebSocket } from '@/utils/socket' const { messages, isConnected, connect, send, disconnect } = useWebSocket( 'ws://localhost:2346' ) const message = ref('') const sendMessage = () => { if (message.value.trim()) { send({ type: 'message', content: message.value, timestamp: Date.now() }) message.value = '' } } </script> ``` #### 三、关键配置说明 1. **跨域处理**:在 Workerman 中需添加 HTTP 头 ```php $worker->onConnect = function ($connection) { $connection->headers = [ 'Access-Control-Allow-Origin' => '*', 'Access-Control-Allow-Methods' => 'GET,POST' ]; }; ``` 2. **用户认证**:在连接时验证用户身份 ```php $worker->onMessage = function ($connection, $data) { $data = json_decode($data, true); if ($data['type'] === 'auth') { $user = Db::name('users')->where('token', $data['token'])->find(); if ($user) { $connection->user_id = $user['id']; } } }; ``` 3. **生产环境配置**: - 使用 Nginx 反向代理 WebSocket - 配置 SSL 证书启用 wss ```nginx location /websocket { proxy_pass http://127.0.0.1:2346; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } ``` #### 四、常见问题解决 1. **连接失败**: - 检查防火墙是否开放端口 `2346` - 确认后端服务已启动 `netstat -tulnp | grep 2346` - 前端使用 `ws://localhost:2346` 开发环境连接 2. **消息格式**: - 推荐统一使用 JSON 格式 - 添加消息类型字段区分指令 ```json { "type": "message|auth|system", "data": {...} } ``` 3. **断线重连**(前端优化): ```javascript let reconnectInterval = null const reconnect = () => { clearInterval(reconnectInterval) reconnectInterval = setInterval(() => { if (!isConnected.value) { console.log('尝试重连...') connect() } }, 5000) } socket.value.onclose = () => { isConnected.value = false reconnect() // 启动重连机制 } ``` > 此方案已实现基础通信功能,实际项目中需扩展:<br> > - 消息持久化存储(MySQL/Redis)<br> > - 用户在线状态管理<br> > - 消息广播/私聊区分<br> > - 心跳检测机制(防止连接超时)[^1][^5] --- ### 相关问题 1. 如何实现 WebSocket 消息的数据库持久化存储? 2. Vue3 中如何处理 WebSocket 的跨域问题? 3. Workerman 如何实现多服务器集群部署? 4. WebSocket 通信中如何保证数据安全性(加密传输)? 5. 如何通过心跳检测维持 WebSocket 长连接稳定性? > 引用说明: > [^1]: 基于 ThinkPHP5 WorkerMan Vue3 实现的简易聊天室 > [^5]: ThinkPHP 和 Vue 基于 Workerman 搭建 WebSocket 服务的完整方案
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值