小菜鸟

java菜鸟号正在起航

PHP8 定界符:多行文本处理的高效工具

在 PHP 开发中,当需要处理多行文本(如 HTML 模板、SQL 语句、JSON 片段等)时,直接使用引号包裹会面临转义字符繁琐、格式混乱等问题。PHP 提供的定界符(Heredoc 和 Nowdoc) 完美解决了这一痛点,支持无转义、保留格式的多行文本定义,是 PHP8 中处理长文本的核心语法之一。本文将详细解析两种定界符的语法规则、使用场景及实战示例。

定界符的核心作用

定界符本质是多行字符串的特殊语法,主要解决以下问题:

  1. 避免频繁转义:无需手动转义文本中的单引号、双引号(如 HTML 标签的 class="box" 无需写成 class=\"box\");
  2. 保留原始格式:文本中的换行、空格、缩进会原样保留,无需手动添加 \n\t
  3. 提升可读性:长文本(如 SQL 语句、模板代码)可按原始格式编写,代码结构更清晰。

PHP 支持两种定界符:Heredoc(支持变量解析)和 Nowdoc(纯文本,不解析变量),二者语法相似但用途不同。

Heredoc:支持变量解析的多行文本

Heredoc 是最常用的定界符,语法上类似 “双引号字符串的多行版本”—— 支持解析文本中的变量、转义字符(如 \n),适合需要动态插入变量的场景(如模板渲染、动态 SQL 生成)。

Heredoc 基础语法

Heredoc 的语法规则严格,需注意以下细节:

阅读全文 »

Python 常用模块:别从头造轮子,这些内置的和第三方的直接拿来用

Python 最值钱的东西就是它的生态——标准库加上 PyPI 上几十万的第三方包,几乎覆盖了你可能遇到的所有需求。

写代码的时候,遇到问题第一反应不应该是”自己怎么实现”,而是”有没有现成的模块可以用”。

文件和路径:os、sys、pathlib

os:跟操作系统打交道

import os

# 路径拼接(跨平台)
path = os.path.join("data", "logs", "app.log")  # data/logs/app.log

# 获取当前目录
os.getcwd()

# 创建目录(存在也不报错)
os.makedirs("data/logs", exist_ok=True)

# 判断文件/目录是否存在
os.path.exists("data.txt")
os.path.isfile("data.txt")
os.path.isdir("data")

# 列出目录内容
os.listdir(".")

# 删除文件
os.remove("temp.txt")

# 环境变量
os.environ.get("PATH")

sys:控制 Python 解释器

import sys

# 命令行参数
# python script.py --name Alice
sys.argv  # ['script.py', '--name', 'Alice']

# 程序退出
sys.exit(1)  # 非0表示异常

# Python 版本检查
if sys.version_info < (3, 8):
    print("需要 Python 3.8+")
    sys.exit(1)

# 模块搜索路径
sys.path
sys.path.append("/my/custom/path")

# 平台信息
sys.platform  # 'linux', 'win32', 'darwin'

pathlib:面向对象的路径操作(推荐)

from pathlib import Path

# 创建路径
p = Path("/home/user/data/file.txt")
home = Path.home()
current = Path.cwd()

# 路径属性
p.name       # 'file.txt'
p.stem       # 'file'
p.suffix     # '.txt'
p.parent     # '/home/user/data'

# 拼接(用 / 运算符)
path = Path("data") / "logs" / "app.log"

# 读写文件(一行搞定)
Path("data.txt").write_text("Hello", encoding="utf-8")
content = Path("data.txt").read_text(encoding="utf-8")

# 遍历文件
for file in Path(".").glob("*.py"):
    print(file)

# 递归遍历
for file in Path(".").rglob("*.txt"):
    print(file)

# 创建目录
Path("data/logs").mkdir(parents=True, exist_ok=True)

# 判断存在
if Path("data.txt").exists():
    Path("data.txt").unlink()  # 删除

os 还是 pathlib pathlib 是新代码的推荐选择,更直观、跨平台更好。老代码里 os.path 也很常见,两种都认识就行。

日期时间:datetime

from datetime import datetime, date, timedelta

# 获取当前时间
now = datetime.now()
today = date.today()

# 格式化输出
now.strftime("%Y-%m-%d %H:%M:%S")  # '2026-07-02 10:30:00'
now.strftime("%Y年%m月%d日")        # '2026年07月02日'

# 字符串转 datetime
dt = datetime.strptime("2026-07-02 10:30:00", "%Y-%m-%d %H:%M:%S")

# 时间计算
tomorrow = now + timedelta(days=1)
next_week = now + timedelta(weeks=1)
yesterday = now - timedelta(days=1)

# 时间差
delta = datetime(2026, 12, 31) - datetime(2026, 1, 1)
delta.days  # 364

# 时间戳
timestamp = now.timestamp()
datetime.fromtimestamp(timestamp)

日期格式符记住 %Y-%m-%d %H:%M:%S 就够了,其他格式遇到再查。

JSON 处理:json

阅读全文 »

Python 文件操作:读写文件这件事,记住 with open 就够了

写程序,文件操作避不开。读配置、写日志、处理数据、导出报表——天天都在跟文件打交道。

Python 的文件操作其实就一件事:with open() 打开文件,然后读或写。语法很简单,但实际用的时候有些细节——编码、大文件、异常处理——不注意就会出问题。

核心原则:永远用 with open

# 推荐写法
with open("data.txt", "r", encoding="utf-8") as f:
    content = f.read()
# 文件自动关闭,不用手动 close

# 不推荐
f = open("data.txt", "r")
content = f.read()
f.close()  # 万一前面报错,close 不会执行

with 语句会在代码块结束后自动关闭文件,即使中间抛异常也一样。记住这一点,就不用操心资源泄露的问题了。

读文件:三种方式,按需取用

1. 小文件:直接读完

with open("config.json", "r", encoding="utf-8") as f:
    content = f.read()

文件不大的时候,这是最直接的写法。几 MB 以内的文件都没问题。

2. 大文件:逐行读,不占内存

with open("large_log.txt", "r", encoding="utf-8") as f:
    for line in f:
        # 处理每一行
        if "ERROR" in line:
            print(line.strip())

for line in f 是逐行读取,不会一次性把所有内容加载到内存。处理几 GB 的日志文件就用这个方式。

3. 读所有行到列表

with open("data.txt", "r", encoding="utf-8") as f:
    lines = f.readlines()
    # lines 是一个列表,每行一个元素
阅读全文 »

Python 单例模式:一个类只能有一个实例,到底怎么实现?

写程序的时候,有些东西全局只能有一份——配置管理器、日志记录器、数据库连接池。如果每个地方都 new 一个,资源浪费不说,状态还不一致。

单例模式就是干这个的:确保一个类在整个程序里只有一个实例,所有人都用它。

单例要解决的问题,先看一个反例

class Config:
    def __init__(self):
        self.settings = {}

config1 = Config()
config1.settings["theme"] = "dark"

config2 = Config()
print(config2.settings)   # {},白存了

config1config2 是两个不同的对象,配置存到 config1 里,config2 拿不到。这就是问题——配置这种全局只有一份的东西,不应该被重复创建。

单例模式要的效果:

config1 = Config()
config2 = Config()
print(config1 is config2)   # True,同一个对象

最简单:模块级单例,利用 Python 的导入机制

Python 的模块在第一次被导入时执行,之后再导入直接用已经加载好的。这是最简单、最 Pythonic 的方式。

config.py

class Config:
    def __init__(self):
        self.settings = {}
    
    def set(self, key, value):
        self.settings[key] = value
    
    def get(self, key):
        return self.settings.get(key)

# 直接在模块里创建一个实例
config = Config()

使用:

from config import config

config.set("theme", "dark")
# 任何其他地方 from config import config 拿到的都是同一个对象

优点: 代码量最少,不需要任何技巧,Python 天然支持。

缺点: 不能延迟初始化(导入的时候实例就创建了),灵活性稍差。

适合场景: 日志记录器、配置管理、工具类等简单场景。大部分时候这就够了,不需要更复杂的实现。

阅读全文 »

Python 的 @classmethod 和 @staticmethod:什么时候用哪个,一次说清楚

写 Python 类的时候,除了普通的实例方法,还有两种带装饰器的方法:@classmethod@staticmethod

刚接触的时候很容易搞混——“不都是类里的方法吗,为什么还要分三种?”

其实区别很简单:实例方法要操作对象,类方法要操作类,静态方法只是”恰好放在这个类里的普通函数”。

先复习一下实例方法:带 self 的那个

class Person:
    species = "人类"
    
    def __init__(self, name):
        self.name = name
    
    def greet(self):
        return f"你好,我是 {self.name}"

实例方法的特点:

  • 第一个参数是 self,指向具体的对象
  • 能访问对象的属性(self.name
  • 能访问类的属性(self.speciesPerson.species
  • 必须通过对象调用

实例方法处理的是”每个对象各自不同的数据”,比如每个人的名字不同。

类方法:@classmethod,操作的是类本身

类方法的第一个参数是 cls,指向类本身,而不是某个具体对象。

class Person:
    count = 0
    
    def __init__(self, name):
        self.name = name
        Person.count += 1
    
    @classmethod
    def get_count(cls):
        return cls.count   # 返回总人数,跟具体对象无关

# 通过类名调用
Person.get_count()   # 0

类方法能访问和修改类属性(所有对象共享的数据),但不能访问实例属性(每个对象各自的数据)。

什么时候用类方法?三种最常见的场景:

场景1:工厂方法——用不同方式创建对象
from datetime import datetime

class Date:
    def __init__(self, year, month, day):
        self.year = year
        self.month = month
        self.day = day
    
    @classmethod
    def from_string(cls, date_str):
        """从 '2024-01-15' 这样的字符串创建日期对象"""
        year, month, day = map(int, date_str.split("-"))
        return cls(year, month, day)
    
    @classmethod
    def today(cls):
        """创建今天的日期"""
        now = datetime.now()
        return cls(now.year, now.month, now.day)

# 用不同方式创建
d1 = Date.from_string("2024-01-15")
d2 = Date.today()
阅读全文 »
0%