I can understand that the player might expose a bounding box (or cylinder, or whatever) and its velocity to allow external collision routines to work out any collisions, and what the collision response should be. Roughly:
bounds, velocity = world.calc_collision_response(player.bounds, player.velocity, dt) player.bounds = bounds player.velocity = velocity
The collision detection/response code is then entirely divorced from the player. This means it can be used for other things too (NPCs, vehicles, ...)
Similarly for weapons. If you've got stuff like sniper rifles, shotguns, etc, all that's really needed is:
rays = player.weapon.get_spread(player.position, player.orientation); // might have many rays for a weapon with 'spread', like a shotgun for ray in rays: target = world.check_ray_hit(ray.origin, ray.direction) if target target.register_hit(ray.force, ray.penetration)
Here, the player's details (position and orientation) are indeed used to calculate what the weapon would hit. But that doesn't mean the weapon has to know about who's holding it. In fact, the code would look exactly the same for the player, or for an NPC.
The code is probably overly simplistic, but you really want to avoid the situation where every class knows about every other class. In other words, you want to reduce coupling. This means that making changes reduces the rippling effect that's often seen when refactoring.
There are other benefits to this kind of separation too. You can group stuff like collision tests together to improve locality and allow vectorization.